mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-08-18 10:58:43 -04:00
Merge pull request #1971 from sehraf/pr_i2p_refactoring
i2p refactoring
This commit is contained in:
commit
891d7e7c9a
11 changed files with 583 additions and 201 deletions
163
libretroshare/src/util/i2pcommon.cpp
Normal file
163
libretroshare/src/util/i2pcommon.cpp
Normal file
|
@ -0,0 +1,163 @@
|
|||
#include "i2pcommon.h"
|
||||
|
||||
#include "util/rsbase64.h"
|
||||
#include "util/rsdebug.h"
|
||||
|
||||
namespace i2p {
|
||||
|
||||
std::string keyToBase32Addr(const std::string &key)
|
||||
{
|
||||
std::string copy(key);
|
||||
|
||||
// replace I2P specific chars
|
||||
std::replace(copy.begin(), copy.end(), '~', '/');
|
||||
// replacing the - with a + is not necessary, as RsBase64 can handle base64url encoding, too
|
||||
// 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) {
|
||||
return lhs + "=" + std::to_string(rhs);
|
||||
}
|
||||
|
||||
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(), '~', '/');
|
||||
// replacing the - with a + is not necessary, as RsBase64 can handle base64url encoding, too
|
||||
// std::replace(copy.begin(), copy.end(), '-', '+');
|
||||
|
||||
// get raw data
|
||||
std::vector<uint8_t> dataPriv;
|
||||
RsBase64::decode(priv_copy, dataPriv);
|
||||
|
||||
auto p = dataPriv.cbegin();
|
||||
RS_DBG("dataPriv.size ", dataPriv.size());
|
||||
|
||||
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!
|
||||
*/
|
||||
RS_DBG("cert is CertType.Null");
|
||||
publicKeyLen += 3; // add 0x00 0x00 0x00
|
||||
|
||||
if (len != 0)
|
||||
// weird
|
||||
RS_DBG("cert is CertType.Null but len != 0");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// check for != 5
|
||||
if (certType != static_cast<typename std::underlying_type<CertType>::type>(CertType::Key)) {
|
||||
// unsupported
|
||||
RS_DBG("cert type ", certType, " is unsupported");
|
||||
return std::string();
|
||||
}
|
||||
|
||||
RS_DBG("cert is CertType.Key");
|
||||
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);
|
||||
|
||||
RS_DBG("signing pubkey type ", certType);
|
||||
if (signingKeyType >= 3 && signingKeyType <= 6) {
|
||||
RS_DBG("signing pubkey type ", certType, " has oversize");
|
||||
// calculate oversize
|
||||
|
||||
if (signingKeyType >= signingKeyLengths.size()) {
|
||||
// just in case
|
||||
RS_DBG("signing pubkey type ", certType, " cannot be found in size data!");
|
||||
return std::string();
|
||||
}
|
||||
|
||||
auto values = signingKeyLengths[signingKeyType];
|
||||
if (values.first <= 128) {
|
||||
// just in case, it's supposed to be larger!
|
||||
RS_DBG("signing pubkey type ", certType, " is oversize but size calculation would underflow!");
|
||||
return std::string();
|
||||
}
|
||||
|
||||
publicKeyLen += values.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);
|
||||
RS_DBG("crypto pubkey type ", cryptKey);
|
||||
// info: these are all smaller than the default 256 bytes, so no oversize calculation is needed
|
||||
|
||||
break;
|
||||
} catch (const std::out_of_range &e) {
|
||||
RS_DBG("hit exception! ", e.what());
|
||||
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
|
211
libretroshare/src/util/i2pcommon.h
Normal file
211
libretroshare/src/util/i2pcommon.h
Normal file
|
@ -0,0 +1,211 @@
|
|||
#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::array<std::pair<uint16_t, uint16_t>, 5> cryptoKeyLengths {
|
||||
/*CryptoKeyType::ElGamal*/ std::make_pair<uint16_t, uint16_t>(256, 256),
|
||||
/*CryptoKeyType::P256, */ std::make_pair<uint16_t, uint16_t>( 64, 32),
|
||||
/*CryptoKeyType::P384, */ std::make_pair<uint16_t, uint16_t>( 96, 48),
|
||||
/*CryptoKeyType::P521, */ std::make_pair<uint16_t, uint16_t>(132, 66),
|
||||
/*CryptoKeyType::X25519,*/ std::make_pair<uint16_t, uint16_t>( 32, 32),
|
||||
};
|
||||
|
||||
static const std::array<std::pair<uint16_t, uint16_t>, 12> signingKeyLengths {
|
||||
/*SigningKeyType::DSA_SHA1, */ std::make_pair<uint16_t, uint16_t>(128, 128),
|
||||
/*SigningKeyType::ECDSA_SHA256_P256, */ std::make_pair<uint16_t, uint16_t>( 64, 32),
|
||||
/*SigningKeyType::ECDSA_SHA384_P384, */ std::make_pair<uint16_t, uint16_t>( 96, 48),
|
||||
/*SigningKeyType::ECDSA_SHA512_P521, */ std::make_pair<uint16_t, uint16_t>(132, 66),
|
||||
/*SigningKeyType::RSA_SHA256_2048, */ std::make_pair<uint16_t, uint16_t>(256, 512),
|
||||
/*SigningKeyType::RSA_SHA384_3072, */ std::make_pair<uint16_t, uint16_t>(384, 768),
|
||||
/*SigningKeyType::RSA_SHA512_4096, */ std::make_pair<uint16_t, uint16_t>(512,1024),
|
||||
/*SigningKeyType::EdDSA_SHA512_Ed25519 */ std::make_pair<uint16_t, uint16_t>( 32, 32),
|
||||
/*SigningKeyType::EdDSA_SHA512_Ed25519ph */ std::make_pair<uint16_t, uint16_t>( 32, 32),
|
||||
/*reserved (GOST) */ std::make_pair<uint16_t, uint16_t>( 64, 0),
|
||||
/*reserved (GOST) */ std::make_pair<uint16_t, uint16_t>(128, 0),
|
||||
/*SigningKeyType::RedDSA_SHA512_Ed25519 */ std::make_pair<uint16_t, uint16_t>( 32, 32),
|
||||
};
|
||||
|
||||
/**
|
||||
* @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…
Add table
Add a link
Reference in a new issue