mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-01-13 08:29:32 -05:00
add helper for i2p related functions
This commit is contained in:
parent
b49dfaead0
commit
462f52585b
@ -154,6 +154,7 @@ rs_webui {
|
||||
HEADERS += plugins/pluginmanager.h \
|
||||
plugins/dlfcn_win32.h \
|
||||
rsitems/rspluginitems.h \
|
||||
util/i2pcommon.h \
|
||||
util/rsinitedptr.h
|
||||
|
||||
HEADERS += $$PUBLIC_HEADERS
|
||||
@ -517,7 +518,8 @@ SOURCES += ft/ftchunkmap.cc \
|
||||
ft/ftfilesearch.cc \
|
||||
ft/ftserver.cc \
|
||||
ft/fttransfermodule.cc \
|
||||
ft/ftturtlefiletransferitem.cc
|
||||
ft/ftturtlefiletransferitem.cc \
|
||||
util/i2pcommon.cpp
|
||||
|
||||
SOURCES += crypto/chacha20.cpp \
|
||||
crypto/hashstream.cc\
|
||||
|
172
libretroshare/src/util/i2pcommon.cpp
Normal file
172
libretroshare/src/util/i2pcommon.cpp
Normal file
@ -0,0 +1,172 @@
|
||||
#include "i2pcommon.h"
|
||||
|
||||
#include "util/rsbase64.h"
|
||||
#include "util/rsdebug.h"
|
||||
|
||||
namespace i2p {
|
||||
|
||||
const std::string generateNameSuffix(const size_t len) {
|
||||
std::vector<uint8_t> tmp(len);
|
||||
RsRandom::random_bytes(tmp.data(), len);
|
||||
const std::string location = Radix32::encode(tmp.data(), len);
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
std::string keyToBase32Addr(const std::string &key)
|
||||
{
|
||||
std::string copy(key);
|
||||
|
||||
// replace I2P specific chars
|
||||
std::replace(copy.begin(), copy.end(), '~', '/');
|
||||
std::replace(copy.begin(), copy.end(), '-', '+');
|
||||
|
||||
// decode
|
||||
std::vector<uint8_t> bin;
|
||||
RsBase64::decode(copy, bin);
|
||||
|
||||
// hash
|
||||
std::vector<uint8_t> sha256 = RsUtil::BinToSha256(bin);
|
||||
// encode
|
||||
std::string out = Radix32::encode(sha256);
|
||||
|
||||
// i2p uses lowercase
|
||||
std::transform(out.begin(), out.end(), out.begin(), ::tolower);
|
||||
out.append(".b32.i2p");
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
const std::string makeOption(const std::string &lhs, const int8_t &rhs) {
|
||||
// convert number to int
|
||||
std::ostringstream oss;
|
||||
oss << (int)rhs;
|
||||
return lhs + "=" + oss.str();
|
||||
}
|
||||
|
||||
uint16_t readTwoBytesBE(std::vector<uint8_t>::const_iterator &p)
|
||||
{
|
||||
uint16_t val = 0;
|
||||
val += *p++;
|
||||
val <<= 8;
|
||||
val += *p++;
|
||||
return val;
|
||||
}
|
||||
|
||||
std::string publicKeyFromPrivate(std::string const &priv)
|
||||
{
|
||||
/*
|
||||
* https://geti2p.net/spec/common-structures#destination
|
||||
* https://geti2p.net/spec/common-structures#keysandcert
|
||||
* https://geti2p.net/spec/common-structures#certificate
|
||||
*/
|
||||
if (priv.length() < 884) // base64 ( = 663 bytes = KeyCert + priv Keys)
|
||||
return std::string();
|
||||
|
||||
// creat a copy to work on, need to convert it to standard base64
|
||||
auto priv_copy(priv);
|
||||
std::replace(priv_copy.begin(), priv_copy.end(), '~', '/');
|
||||
std::replace(priv_copy.begin(), priv_copy.end(), '-', '+');
|
||||
|
||||
// get raw data
|
||||
std::vector<uint8_t> dataPriv;
|
||||
RsBase64::decode(priv_copy, dataPriv);
|
||||
|
||||
auto p = dataPriv.cbegin();
|
||||
RsDbg() << __PRETTY_FUNCTION__ << " dataPriv.size " << dataPriv.size() << std::endl;
|
||||
|
||||
size_t publicKeyLen = 256 + 128; // default length (bytes)
|
||||
uint8_t certType = 0;
|
||||
uint16_t len = 0;
|
||||
uint16_t signingKeyType = 0;
|
||||
uint16_t cryptKey = 0;
|
||||
|
||||
// only used for easy break
|
||||
do {
|
||||
try {
|
||||
// jump to certificate
|
||||
p += publicKeyLen;
|
||||
// try to read type and length
|
||||
certType = *p++;
|
||||
len = readTwoBytesBE(p);
|
||||
|
||||
// only 0 and 5 are used / valid at this point
|
||||
// check for == 0
|
||||
if (certType == static_cast<typename std::underlying_type<CertType>::type>(CertType::Null)) {
|
||||
/*
|
||||
* CertType.Null
|
||||
* type null is followed by 0x00 0x00 <END>
|
||||
* so has to be 0!
|
||||
*/
|
||||
RsDbg() << __PRETTY_FUNCTION__ << " cert is CertType.Null" << std::endl;
|
||||
publicKeyLen += 3; // add 0x00 0x00 0x00
|
||||
|
||||
if (len != 0)
|
||||
// weird
|
||||
RsDbg() << __PRETTY_FUNCTION__ << " cert is CertType.Null but len != 0" << std::endl;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// check for != 5
|
||||
if (certType != static_cast<typename std::underlying_type<CertType>::type>(CertType::Key)) {
|
||||
// unsupported
|
||||
RsDbg() << __PRETTY_FUNCTION__ << " cert type " << certType << " is unsupported" << std::endl;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
RsDbg() << __PRETTY_FUNCTION__ << " cert is CertType.Key" << std::endl;
|
||||
publicKeyLen += 7; // <type 1B> <len 2B> <keyType1 2B> <keyType2 2B> = 1 + 2 + 2 + 2 = 7 bytes
|
||||
|
||||
/*
|
||||
* "Key certificates were introduced in release 0.9.12. Prior to that release, all PublicKeys were 256-byte ElGamal keys, and all SigningPublicKeys were 128-byte DSA-SHA1 keys."
|
||||
* --> there is space for 256+128 bytes, longer keys are splitted and appended to the certificate
|
||||
* We don't need to bother with the splitting here as only the lenght is important!
|
||||
*/
|
||||
|
||||
// Signing Public Key
|
||||
// likely 7
|
||||
signingKeyType = readTwoBytesBE(p);
|
||||
|
||||
RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << std::endl;
|
||||
if (signingKeyType >= 3 && signingKeyType <= 6) {
|
||||
RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << " has oversize" << std::endl;
|
||||
// calculate oversize
|
||||
|
||||
auto it = signingKeyLengths.find(static_cast<SigningKeyType>(signingKeyType));
|
||||
if (it == signingKeyLengths.end()) {
|
||||
// just in case
|
||||
RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << " cannot be found in size map!" << std::endl;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
if (it->second.first <= 128) {
|
||||
// just in case, it's supposed to be larger!
|
||||
RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << " is oversize but size calculation would underflow!" << std::endl;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
publicKeyLen += it->second.first - 128; // 128 = default DSA key length = the space than can be used before the key must be splitted
|
||||
}
|
||||
|
||||
// Crypto Public Key
|
||||
// likely 0
|
||||
cryptKey = readTwoBytesBE(p);
|
||||
RsDbg() << __PRETTY_FUNCTION__ << " crypto pubkey type " << cryptKey << std::endl;
|
||||
// info: these are all smaller than the default 256 bytes, so no oversize calculation is needed
|
||||
|
||||
break;
|
||||
} catch (const std::out_of_range &e) {
|
||||
RsDbg() << __PRETTY_FUNCTION__ << " hit exception!" << e.what() << std::endl;
|
||||
return std::string();
|
||||
}
|
||||
} while(false);
|
||||
|
||||
std::string pub;
|
||||
auto data2 = std::vector<uint8_t>(dataPriv.cbegin(), dataPriv.cbegin() + publicKeyLen);
|
||||
RsBase64::encode(data2.data(), data2.size(), pub, false, false);
|
||||
|
||||
return pub;
|
||||
}
|
||||
|
||||
} // namespace i2p
|
222
libretroshare/src/util/i2pcommon.h
Normal file
222
libretroshare/src/util/i2pcommon.h
Normal file
@ -0,0 +1,222 @@
|
||||
#ifndef I2PCOMMON_H
|
||||
#define I2PCOMMON_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#include "util/rsrandom.h"
|
||||
#include "util/radix32.h"
|
||||
#include "util/rsbase64.h"
|
||||
#include "util/rsprint.h"
|
||||
#include "util/rsdebug.h"
|
||||
|
||||
/*
|
||||
* This header provides common code for i2p related code, namely BOB and SAM3 support.
|
||||
*/
|
||||
|
||||
namespace i2p {
|
||||
|
||||
static constexpr int8_t kDefaultLength = 3; // i2p default
|
||||
static constexpr int8_t kDefaultQuantity = 3; // i2p default + 1
|
||||
static constexpr int8_t kDefaultVariance = 0;
|
||||
static constexpr int8_t kDefaultBackupQuantity = 0;
|
||||
|
||||
/**
|
||||
* @brief The address struct
|
||||
* This structure is a container for any i2p address/key. The public key is used for addressing and can be (optionally) hashed to generate the .b32.i2p address.
|
||||
*/
|
||||
struct address {
|
||||
std::string base32;
|
||||
std::string publicKey;
|
||||
std::string privateKey;
|
||||
|
||||
void clear() {
|
||||
base32.clear();
|
||||
publicKey.clear();
|
||||
privateKey.clear();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The settings struct
|
||||
* Common structure with all settings that are shared between any i2p backends
|
||||
*/
|
||||
struct settings {
|
||||
bool enable;
|
||||
struct address address;
|
||||
|
||||
// connection parameter
|
||||
int8_t inLength;
|
||||
int8_t inQuantity;
|
||||
int8_t inVariance;
|
||||
int8_t inBackupQuantity;
|
||||
|
||||
int8_t outLength;
|
||||
int8_t outQuantity;
|
||||
int8_t outVariance;
|
||||
int8_t outBackupQuantity;
|
||||
|
||||
void initDefault() {
|
||||
enable = false;
|
||||
address.clear();
|
||||
|
||||
inLength = kDefaultLength;
|
||||
inQuantity = kDefaultQuantity;
|
||||
inVariance = kDefaultVariance;
|
||||
inBackupQuantity = kDefaultBackupQuantity;
|
||||
|
||||
outLength = kDefaultLength;
|
||||
outQuantity = kDefaultQuantity;
|
||||
outVariance = kDefaultVariance;
|
||||
outBackupQuantity = kDefaultBackupQuantity;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Type Type Code Payload Length Total Length Notes
|
||||
Null 0 0 3
|
||||
HashCash 1 varies varies Experimental, unused. Payload contains an ASCII colon-separated hashcash string.
|
||||
Hidden 2 0 3 Experimental, unused. Hidden routers generally do not announce that they are hidden.
|
||||
Signed 3 40 or 72 43 or 75 Experimental, unused. Payload contains a 40-byte DSA signature, optionally followed by the 32-byte Hash of the signing Destination.
|
||||
Multiple 4 varies varies Experimental, unused. Payload contains multiple certificates.
|
||||
Key 5 4+ 7+ Since 0.9.12. See below for details.
|
||||
*/
|
||||
enum class CertType : uint8_t {
|
||||
Null = 0,
|
||||
HashCash = 1,
|
||||
Hidden = 2,
|
||||
Signed = 3,
|
||||
Multiple = 4,
|
||||
Key = 5
|
||||
};
|
||||
|
||||
/*
|
||||
* public
|
||||
Type Type Code Total Public Key Length Since Usage
|
||||
DSA_SHA1 0 128 0.9.12 Legacy Router Identities and Destinations, never explicitly set
|
||||
ECDSA_SHA256_P256 1 64 0.9.12 Older Destinations
|
||||
ECDSA_SHA384_P384 2 96 0.9.12 Rarely if ever used for Destinations
|
||||
ECDSA_SHA512_P521 3 132 0.9.12 Rarely if ever used for Destinations
|
||||
RSA_SHA256_2048 4 256 0.9.12 Offline only; never used in Key Certificates for Router Identities or Destinations
|
||||
RSA_SHA384_3072 5 384 0.9.12 Offline only; never used in Key Certificates for Router Identities or Destinations
|
||||
RSA_SHA512_4096 6 512 0.9.12 Offline only; never used in Key Certificates for Router Identities or Destinations
|
||||
EdDSA_SHA512_Ed25519 7 32 0.9.15 Recent Router Identities and Destinations
|
||||
EdDSA_SHA512_Ed25519ph 8 32 0.9.25 Offline only; never used in Key Certificates for Router Identities or Destinations
|
||||
reserved (GOST) 9 64 Reserved, see proposal 134
|
||||
reserved (GOST) 10 128 Reserved, see proposal 134
|
||||
RedDSA_SHA512_Ed25519 11 32 0.9.39 For Destinations and encrypted leasesets only; never used for Router Identities
|
||||
reserved 65280-65534 Reserved for experimental use
|
||||
reserved 65535 Reserved for future expansion
|
||||
|
||||
* private
|
||||
Type Length (bytes) Since Usage
|
||||
DSA_SHA1 20 Legacy Router Identities and Destinations
|
||||
ECDSA_SHA256_P256 32 0.9.12 Recent Destinations
|
||||
ECDSA_SHA384_P384 48 0.9.12 Rarely used for Destinations
|
||||
ECDSA_SHA512_P521 66 0.9.12 Rarely used for Destinations
|
||||
RSA_SHA256_2048 512 0.9.12 Offline signing, never used for Router Identities or Destinations
|
||||
RSA_SHA384_3072 768 0.9.12 Offline signing, never used for Router Identities or Destinations
|
||||
RSA_SHA512_4096 1024 0.9.12 Offline signing, never used for Router Identities or Destinations
|
||||
EdDSA_SHA512_Ed25519 32 0.9.15 Recent Router Identities and Destinations
|
||||
EdDSA_SHA512_Ed25519ph 32 0.9.25 Offline signing, never used for Router Identities or Destinations
|
||||
RedDSA_SHA512_Ed25519 32 0.9.39 For Destinations and encrypted leasesets only, never used for Router Identities
|
||||
*/
|
||||
enum class SigningKeyType : uint16_t {
|
||||
DSA_SHA1 = 0,
|
||||
ECDSA_SHA256_P256 = 1,
|
||||
ECDSA_SHA384_P384 = 2,
|
||||
ECDSA_SHA512_P521 = 3,
|
||||
RSA_SHA256_2048 = 4,
|
||||
RSA_SHA384_3072 = 5,
|
||||
RSA_SHA512_4096 = 6,
|
||||
EdDSA_SHA512_Ed25519 = 7,
|
||||
EdDSA_SHA512_Ed25519ph = 8,
|
||||
RedDSA_SHA512_Ed25519 = 11
|
||||
};
|
||||
|
||||
/*
|
||||
* public
|
||||
Type Type Code Total Public Key Length Usage
|
||||
ElGamal 0 256 All Router Identities and Destinations
|
||||
P256 1 64 Reserved, see proposal 145
|
||||
P384 2 96 Reserved, see proposal 145
|
||||
P521 3 132 Reserved, see proposal 145
|
||||
X25519 4 32 Not for use in key certs. See proposal 144
|
||||
reserved 65280-65534 Reserved for experimental use
|
||||
reserved 65535 Reserved for future expansion
|
||||
|
||||
* private
|
||||
Type Length (bytes) Since Usage
|
||||
ElGamal 256 All Router Identities and Destinations
|
||||
P256 32 TBD Reserved, see proposal 145
|
||||
P384 48 TBD Reserved, see proposal 145
|
||||
P521 66 TBD Reserved, see proposal 145
|
||||
X25519 32 0.9.38 Little-endian. See proposal 144
|
||||
*/
|
||||
enum class CryptoKeyType : uint16_t {
|
||||
ElGamal = 0,
|
||||
P256 = 1,
|
||||
P384 = 2,
|
||||
P521 = 3,
|
||||
X25519 = 4
|
||||
};
|
||||
|
||||
static const std::map<CryptoKeyType, std::pair<uint16_t, uint16_t>> cryptoKeyLengths {
|
||||
{CryptoKeyType::ElGamal, {256, 256}},
|
||||
{CryptoKeyType::P256, { 64, 32}},
|
||||
{CryptoKeyType::P384, { 96, 48}},
|
||||
{CryptoKeyType::P521, {132, 66}},
|
||||
{CryptoKeyType::X25519, { 32, 32}},
|
||||
};
|
||||
|
||||
static const std::map<SigningKeyType, std::pair<uint16_t, uint16_t>> signingKeyLengths {
|
||||
{SigningKeyType::DSA_SHA1, {128, 128}},
|
||||
{SigningKeyType::ECDSA_SHA256_P256, { 64, 32}},
|
||||
{SigningKeyType::ECDSA_SHA384_P384, { 96, 48}},
|
||||
{SigningKeyType::ECDSA_SHA512_P521, {132, 66}},
|
||||
{SigningKeyType::RSA_SHA256_2048, {256, 512}},
|
||||
{SigningKeyType::RSA_SHA384_3072, {384, 768}},
|
||||
{SigningKeyType::RSA_SHA512_4096, {512,1024}},
|
||||
{SigningKeyType::EdDSA_SHA512_Ed25519, { 32, 32}},
|
||||
{SigningKeyType::EdDSA_SHA512_Ed25519ph,{ 32, 32}},
|
||||
{SigningKeyType::RedDSA_SHA512_Ed25519, { 32, 32}},
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief generateNameSuffix Generates a base32 name suffix for tunnel identification
|
||||
* @param len lenght of random bytes, will be expanded by base32 encoding
|
||||
* @return base32 string
|
||||
*
|
||||
* RSRandom::random_alphaNumericString can return very weird looking strings like: ,,@z+M
|
||||
* -> so use base32 instead
|
||||
*
|
||||
* 5 characters = 8 base32 symbols
|
||||
*/
|
||||
const std::string generateNameSuffix(const size_t len = 5);
|
||||
|
||||
/**
|
||||
* @brief makeOption Creates the string "lhs=rhs" used by BOB and SAM. Converts rhs
|
||||
* @param lhs option to set
|
||||
* @param rhs value to set
|
||||
* @return concatenated string
|
||||
*/
|
||||
const std::string makeOption(const std::string &lhs, const int8_t &rhs);
|
||||
|
||||
/**
|
||||
* @brief keyToBase32Addr generated a base32 address (.b32.i2p) from a given public key
|
||||
* @param key public key
|
||||
* @return generated base32 address
|
||||
*/
|
||||
std::string keyToBase32Addr(const std::string &key);
|
||||
|
||||
/**
|
||||
* @brief publicKeyFromPrivate parses the private key and calculates the lenght of the public key
|
||||
* @param priv private key (which includes the public key) to read
|
||||
* @return public key used for addressing
|
||||
*/
|
||||
std::string publicKeyFromPrivate(const std::string &priv);
|
||||
|
||||
} // namespace i2p
|
||||
|
||||
#endif // I2PCOMMON_H
|
Loading…
Reference in New Issue
Block a user