Browse Source

Merge pull request #839 from PurpleI2P/openssl

recent changes
pull/63/merge
orignal 7 years ago committed by GitHub
parent
commit
b2d2c56a09
  1. 6
      BOB.cpp
  2. 18
      Config.cpp
  3. 2
      Config.h
  4. 2
      Crypto.cpp
  5. 2
      Crypto.h
  6. 4
      DaemonLinux.cpp
  7. 99
      Gost.cpp
  8. 9
      Gost.h
  9. 52
      Identity.cpp
  10. 11
      Identity.h
  11. 3
      Makefile.linux
  12. 59
      SAM.cpp
  13. 11
      SAM.h
  14. 30
      Signature.cpp
  15. 30
      Signature.h
  16. 14
      Streaming.cpp
  17. 4
      Streaming.h
  18. 2
      api.cpp
  19. 1
      appveyor.yml
  20. 3
      build/.gitignore
  21. 62
      build/build_mingw.cmd
  22. 2
      contrib/.gitignore
  23. 25
      contrib/build_mingw.cmd
  24. 88
      contrib/build_mingw.sh
  25. 9
      tests/Makefile
  26. 35
      tests/test-gost-sig.cpp
  27. 69
      tests/test-gost.cpp

6
BOB.cpp

@ -430,8 +430,10 @@ namespace client
void BOBCommandSession::SetkeysCommandHandler (const char * operand, size_t len) void BOBCommandSession::SetkeysCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: setkeys ", operand); LogPrint (eLogDebug, "BOB: setkeys ", operand);
m_Keys.FromBase64 (operand); if (m_Keys.FromBase64 (operand))
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ()); SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
else
SendReplyError ("invalid keys");
} }
void BOBCommandSession::GetkeysCommandHandler (const char * operand, size_t len) void BOBCommandSession::GetkeysCommandHandler (const char * operand, size_t len)

18
Config.cpp

@ -238,18 +238,26 @@ namespace config {
; ;
} }
void ParseCmdline(int argc, char* argv[]) { void ParseCmdline(int argc, char* argv[], bool ignoreUnknown)
try { {
try
{
auto style = boost::program_options::command_line_style::unix_style auto style = boost::program_options::command_line_style::unix_style
| boost::program_options::command_line_style::allow_long_disguise; | boost::program_options::command_line_style::allow_long_disguise;
style &= ~ boost::program_options::command_line_style::allow_guessing; style &= ~ boost::program_options::command_line_style::allow_guessing;
store(parse_command_line(argc, argv, m_OptionsDesc, style), m_Options); if (ignoreUnknown)
} catch (boost::program_options::error& e) { store(command_line_parser(argc, argv).options(m_OptionsDesc).style (style).allow_unregistered().run(), m_Options);
else
store(parse_command_line(argc, argv, m_OptionsDesc, style), m_Options);
}
catch (boost::program_options::error& e)
{
std::cerr << "args: " << e.what() << std::endl; std::cerr << "args: " << e.what() << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (m_Options.count("help") || m_Options.count("h")) { if (!ignoreUnknown && (m_Options.count("help") || m_Options.count("h")))
{
std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl; std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl;
std::cout << m_OptionsDesc; std::cout << m_OptionsDesc;
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);

2
Config.h

@ -41,7 +41,7 @@ namespace config {
* *
* Other exceptions will be passed to higher level. * Other exceptions will be passed to higher level.
*/ */
void ParseCmdline(int argc, char* argv[]); void ParseCmdline(int argc, char* argv[], bool ignoreUnknown = false);
/** /**
* @brief Load and parse given config file * @brief Load and parse given config file

2
Crypto.cpp

@ -799,7 +799,7 @@ namespace crypto
}*/ }*/
void InitCrypto (bool precomputation, bool withGost) void InitCrypto (bool precomputation)
{ {
SSL_library_init (); SSL_library_init ();
/* auto numLocks = CRYPTO_num_locks(); /* auto numLocks = CRYPTO_num_locks();

2
Crypto.h

@ -279,7 +279,7 @@ namespace crypto
#endif #endif
}; };
void InitCrypto (bool precomputation, bool withGost = false); void InitCrypto (bool precomputation);
void TerminateCrypto (); void TerminateCrypto ();
} }
} }

4
DaemonLinux.cpp

@ -42,6 +42,9 @@ void handle_signal(int sig)
case SIGTERM: case SIGTERM:
Daemon.running = 0; // Exit loop Daemon.running = 0; // Exit loop
break; break;
case SIGPIPE:
LogPrint(eLogInfo, "SIGPIPE received");
break;
} }
} }
@ -160,6 +163,7 @@ namespace i2p
sigaction(SIGABRT, &sa, 0); sigaction(SIGABRT, &sa, 0);
sigaction(SIGTERM, &sa, 0); sigaction(SIGTERM, &sa, 0);
sigaction(SIGINT, &sa, 0); sigaction(SIGINT, &sa, 0);
sigaction(SIGPIPE, &sa, 0);
return Daemon_Singleton::start(); return Daemon_Singleton::start();
} }

99
Gost.cpp

@ -2,6 +2,7 @@
#include <array> #include <array>
#include <openssl/sha.h> #include <openssl/sha.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include "I2PEndian.h"
#include "Gost.h" #include "Gost.h"
namespace i2p namespace i2p
@ -95,6 +96,38 @@ namespace crypto
return ret; return ret;
} }
EC_POINT * GOSTR3410Curve::RecoverPublicKey (const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s, bool isNegativeY) const
{
// s*P = r*Q + h*C
BN_CTX * ctx = BN_CTX_new ();
BN_CTX_start (ctx);
EC_POINT * C = EC_POINT_new (m_Group); // C = k*P = (rx, ry)
EC_POINT * Q = nullptr;
if (EC_POINT_set_compressed_coordinates_GFp (m_Group, C, r, isNegativeY ? 1 : 0, ctx))
{
EC_POINT * S = EC_POINT_new (m_Group); // S = s*P
EC_POINT_mul (m_Group, S, s, nullptr, nullptr, ctx);
BIGNUM * q = BN_CTX_get (ctx);
EC_GROUP_get_order(m_Group, q, ctx);
BIGNUM * h = BN_CTX_get (ctx);
BN_mod (h, digest, q, ctx); // h = digest % q
BN_sub (h, q, h); // h = -h
EC_POINT * H = EC_POINT_new (m_Group);
EC_POINT_mul (m_Group, H, nullptr, C, h, ctx); // -h*C
EC_POINT_add (m_Group, C, S, H, ctx); // s*P - h*C
EC_POINT_free (H);
EC_POINT_free (S);
BIGNUM * r1 = BN_CTX_get (ctx);
BN_mod_inverse (r1, r, q, ctx);
Q = EC_POINT_new (m_Group);
EC_POINT_mul (m_Group, Q, nullptr, C, r1, ctx); // (s*P - h*C)/r
}
EC_POINT_free (C);
BN_CTX_end (ctx);
BN_CTX_free (ctx);
return Q;
}
static GOSTR3410Curve * CreateGOSTR3410Curve (GOSTR3410ParamSet paramSet) static GOSTR3410Curve * CreateGOSTR3410Curve (GOSTR3410ParamSet paramSet)
{ {
// a, b, p, q, x, y // a, b, p, q, x, y
@ -107,15 +140,7 @@ namespace crypto
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893",
"1", "1",
"8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14" "8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14"
}, // A }, // CryptoPro A
{
"C2173F1513981673AF4892C23035A27CE25E2013BF95AA33B22C656F277E7335",
"295F9BAE7428ED9CCC20E7C359A9D41A22FCCD9108E17BF7BA9337A6F8AE9513",
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97",
"400000000000000000000000000000000FD8CDDFC87B6635C115AF556C360C67",
"0D",
"32879423AB1A0375895786C4BB46E9565FDE0B5344766740AF268ADB32322E5C"
}, // tc26-2012-paramSetA-256
{ {
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4",
"E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760", "E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760",
@ -192,20 +217,7 @@ namespace crypto
0x492c024284fbaec0, 0xaa16012142f35760, 0x550b8e9e21f7a530, 0xa48b474f9ef5dc18, 0x492c024284fbaec0, 0xaa16012142f35760, 0x550b8e9e21f7a530, 0xa48b474f9ef5dc18,
0x70a6a56e2440598e, 0x3853dc371220a247, 0x1ca76e95091051ad, 0x0edd37c48a08a6d8, 0x70a6a56e2440598e, 0x3853dc371220a247, 0x1ca76e95091051ad, 0x0edd37c48a08a6d8,
0x07e095624504536c, 0x8d70c431ac02a736, 0xc83862965601dd1b, 0x641c314b2b8ee083 0x07e095624504536c, 0x8d70c431ac02a736, 0xc83862965601dd1b, 0x641c314b2b8ee083
}; };
static const uint8_t T_[64]=
{
0, 8, 16, 24, 32, 40, 48, 56,
1, 9, 17, 25, 33, 41, 49, 57,
2, 10, 18, 26, 34, 42, 50, 58,
3, 11, 19, 27, 35, 43, 51, 59,
4, 12, 20, 28, 36, 44, 52, 60,
5, 13, 21, 29, 37, 45, 53, 61,
6, 14, 22, 30, 38, 46, 54, 62,
7, 15, 23, 31, 39, 47, 55, 63
};
static const uint8_t C_[12][64] = static const uint8_t C_[12][64] =
{ {
@ -327,51 +339,36 @@ namespace crypto
} }
} }
void S () void SPL ()
{
for (int i = 0; i < 64; i++)
buf[i] = sbox_[buf[i]];
}
void L ()
{ {
uint8_t p[64];
memcpy (p, buf, 64); // we need to copy it for P's transposition
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
uint64_t c = 0; uint64_t c = 0;
for (int j = 0; j < 8; j++) for (int j = 0; j < 8; j++)
{ {
uint8_t bit = 0x80; uint8_t bit = 0x80;
uint8_t byte = sbox_[p[j*8+i]]; // S - sbox_, P - transpose (i,j)
for (int k = 0; k < 8; k++) for (int k = 0; k < 8; k++)
{ {
if (buf[i*8+j] & bit) c ^= A_[j*8+k]; if (byte & bit) c ^= A_[j*8+k];
bit >>= 1; bit >>= 1;
} }
} }
ll[i] = c; ll[i] = htobe64 (c);
} }
} }
void P ()
{
uint8_t t[64];
for (int i = 0; i < 64; i++)
t[i] = buf[T_[i]];
memcpy (buf, t, 64);
}
GOST3411Block E (const GOST3411Block& m) GOST3411Block E (const GOST3411Block& m)
{ {
GOST3411Block k = *this; GOST3411Block k = *this;
GOST3411Block res = k^m; GOST3411Block res = k^m;
for (int i = 0; i < 12; i++) for (int i = 0; i < 12; i++)
{ {
res.S (); res.SPL ();
res.P ();
res.L ();
k = k^C_[i]; k = k^C_[i];
k.S (); k.SPL ();
k.P ();
k.L ();
res = k^res; res = k^res;
} }
return res; return res;
@ -381,12 +378,10 @@ namespace crypto
static GOST3411Block gN (const GOST3411Block& N, const GOST3411Block& h, const GOST3411Block& m) static GOST3411Block gN (const GOST3411Block& N, const GOST3411Block& h, const GOST3411Block& m)
{ {
GOST3411Block res = N ^ h; GOST3411Block res = N ^ h;
res.S (); res.SPL ();
res.P ();
res.L ();
res = res.E (m); res = res.E (m);
res = res ^ h; res = res^h;
res = res ^ m; res = res^m;
return res; return res;
} }
@ -405,7 +400,7 @@ namespace crypto
h= gN (N, h, m); h= gN (N, h, m);
N.Add (512); N.Add (512);
s = m + s; s = m + s;
len -= 64; l -= 64;
} }
// stage 3 // stage 3
size_t padding = 64 - l; size_t padding = 64 - l;

9
Gost.h

@ -13,13 +13,10 @@ namespace crypto
enum GOSTR3410ParamSet enum GOSTR3410ParamSet
{ {
// GOST R 34.10-2001
eGOSTR3410CryptoProA = 0, // 1.2.643.2.2.35.1 eGOSTR3410CryptoProA = 0, // 1.2.643.2.2.35.1
// XchA = A, XchB = C // XchA = A, XchB = C
//eGOSTR3410CryptoProXchA, // 1.2.643.2.2.36.0 //eGOSTR3410CryptoProXchA, // 1.2.643.2.2.36.0
//eGOSTR3410CryptoProXchB, // 1.2.643.2.2.36.1 //eGOSTR3410CryptoProXchB, // 1.2.643.2.2.36.1
// GOST R 34.10-2012
eGOSTR3410TC26A256, // 1.2.643.7.1.2.1.1.1
eGOSTR3410TC26A512, // 1.2.643.7.1.2.1.2.1 eGOSTR3410TC26A512, // 1.2.643.7.1.2.1.2.1
eGOSTR3410NumParamSets eGOSTR3410NumParamSets
}; };
@ -32,11 +29,13 @@ namespace crypto
~GOSTR3410Curve (); ~GOSTR3410Curve ();
size_t GetKeyLen () const { return m_KeyLen; }; size_t GetKeyLen () const { return m_KeyLen; };
const EC_GROUP * GetGroup () const { return m_Group; };
EC_POINT * MulP (const BIGNUM * n) const; EC_POINT * MulP (const BIGNUM * n) const;
bool GetXY (const EC_POINT * p, BIGNUM * x, BIGNUM * y) const; bool GetXY (const EC_POINT * p, BIGNUM * x, BIGNUM * y) const;
EC_POINT * CreatePoint (const BIGNUM * x, const BIGNUM * y) const; EC_POINT * CreatePoint (const BIGNUM * x, const BIGNUM * y) const;
void Sign (const BIGNUM * priv, const BIGNUM * digest, BIGNUM * r, BIGNUM * s); void Sign (const BIGNUM * priv, const BIGNUM * digest, BIGNUM * r, BIGNUM * s);
bool Verify (const EC_POINT * pub, const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s); bool Verify (const EC_POINT * pub, const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s);
EC_POINT * RecoverPublicKey (const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s, bool isNegativeY = false) const;
private: private:
@ -47,7 +46,7 @@ namespace crypto
std::unique_ptr<GOSTR3410Curve>& GetGOSTR3410Curve (GOSTR3410ParamSet paramSet); std::unique_ptr<GOSTR3410Curve>& GetGOSTR3410Curve (GOSTR3410ParamSet paramSet);
void GOSTR3411_2012_256 (const uint8_t * buf, size_t len, uint8_t * digest); void GOSTR3411_2012_256 (const uint8_t * buf, size_t len, uint8_t * digest);
void GOSTR3411_2012_512 (const uint8_t * buf, size_t len, uint8_t * digest); void GOSTR3411_2012_512 (const uint8_t * buf, size_t len, uint8_t * digest);
} }
} }

52
Identity.cpp

@ -102,8 +102,8 @@ namespace data
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH); memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH);
break; break;
} }
case SIGNING_KEY_TYPE_GOSTR3410_2001_CRYPTO_PRO_A_GOSTR3411: case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256:
case SIGNING_KEY_TYPE_GOSTR3410_2012_TC26_A_256_GOSTR3411: case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST:
{ {
// 256 // 256
size_t padding = 128 - i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH; // 64 = 128 - 64 size_t padding = 128 - i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH; // 64 = 128 - 64
@ -111,7 +111,8 @@ namespace data
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH); memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH);
break; break;
} }
case SIGNING_KEY_TYPE_GOSTR3410_2012_TC26_A_512_GOSTR3411: case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512_TEST:
{ {
// 512 // 512
// no padding, key length is 128 // no padding, key length is 128
@ -386,22 +387,18 @@ namespace data
UpdateVerifier (new i2p::crypto::EDDSA25519Verifier (m_StandardIdentity.signingKey + padding)); UpdateVerifier (new i2p::crypto::EDDSA25519Verifier (m_StandardIdentity.signingKey + padding));
break; break;
} }
case SIGNING_KEY_TYPE_GOSTR3410_2001_CRYPTO_PRO_A_GOSTR3411: case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256:
case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST:
{ {
size_t padding = 128 - i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH; // 64 = 128 - 64 size_t padding = 128 - i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH; // 64 = 128 - 64
UpdateVerifier (new i2p::crypto::GOSTR3410_2001_Verifier (i2p::crypto::eGOSTR3410CryptoProA, m_StandardIdentity.signingKey + padding)); UpdateVerifier (new i2p::crypto::GOSTR3410_256_Verifier (i2p::crypto::eGOSTR3410CryptoProA, m_StandardIdentity.signingKey + padding));
break;
}
case SIGNING_KEY_TYPE_GOSTR3410_2012_TC26_A_256_GOSTR3411:
{
size_t padding = 128 - i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH; // 64 = 128 - 64
UpdateVerifier (new i2p::crypto::GOSTR3410_2012_256_Verifier (i2p::crypto::eGOSTR3410TC26A256, m_StandardIdentity.signingKey + padding));
break; break;
} }
case SIGNING_KEY_TYPE_GOSTR3410_2012_TC26_A_512_GOSTR3411: case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512_TEST:
{ {
// zero padding // zero padding
UpdateVerifier (new i2p::crypto::GOSTR3410_2012_512_Verifier (i2p::crypto::eGOSTR3410TC26A512, m_StandardIdentity.signingKey)); UpdateVerifier (new i2p::crypto::GOSTR3410_512_Verifier (i2p::crypto::eGOSTR3410TC26A512, m_StandardIdentity.signingKey));
break; break;
} }
default: default:
@ -462,8 +459,9 @@ namespace data
size_t PrivateKeys::FromBuffer (const uint8_t * buf, size_t len) size_t PrivateKeys::FromBuffer (const uint8_t * buf, size_t len)
{ {
m_Public = std::make_shared<IdentityEx>(buf, len); m_Public = std::make_shared<IdentityEx>();
size_t ret = m_Public->GetFullLen (); size_t ret = m_Public->FromBuffer (buf, len);
if (!ret || ret + 256 > len) return 0; // overflow
memcpy (m_PrivateKey, buf + ret, 256); // private key always 256 memcpy (m_PrivateKey, buf + ret, 256); // private key always 256
ret += 256; ret += 256;
size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen (); size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen ();
@ -545,14 +543,13 @@ namespace data
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().certificate - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH)); m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().certificate - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH));
break; break;
case SIGNING_KEY_TYPE_GOSTR3410_2001_CRYPTO_PRO_A_GOSTR3411: case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256:
m_Signer.reset (new i2p::crypto::GOSTR3410_2001_Signer (i2p::crypto::eGOSTR3410CryptoProA, m_SigningPrivateKey)); case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST:
break; m_Signer.reset (new i2p::crypto::GOSTR3410_256_Signer (i2p::crypto::eGOSTR3410CryptoProA, m_SigningPrivateKey));
case SIGNING_KEY_TYPE_GOSTR3410_2012_TC26_A_256_GOSTR3411:
m_Signer.reset (new i2p::crypto::GOSTR3410_2012_256_Signer (i2p::crypto::eGOSTR3410TC26A256, m_SigningPrivateKey));
break; break;
case SIGNING_KEY_TYPE_GOSTR3410_2012_TC26_A_512_GOSTR3411: case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
m_Signer.reset (new i2p::crypto::GOSTR3410_2012_512_Signer (i2p::crypto::eGOSTR3410TC26A512, m_SigningPrivateKey)); case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512_TEST:
m_Signer.reset (new i2p::crypto::GOSTR3410_512_Signer (i2p::crypto::eGOSTR3410TC26A512, m_SigningPrivateKey));
break; break;
default: default:
LogPrint (eLogError, "Identity: Signing key type ", (int)m_Public->GetSigningKeyType (), " is not supported"); LogPrint (eLogError, "Identity: Signing key type ", (int)m_Public->GetSigningKeyType (), " is not supported");
@ -588,14 +585,13 @@ namespace data
break; break;
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
i2p::crypto::CreateEDDSA25519RandomKeys (keys.m_SigningPrivateKey, signingPublicKey); i2p::crypto::CreateEDDSA25519RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_GOSTR3410_2001_CRYPTO_PRO_A_GOSTR3411:
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410CryptoProA, keys.m_SigningPrivateKey, signingPublicKey);
break; break;
case SIGNING_KEY_TYPE_GOSTR3410_2012_TC26_A_256_GOSTR3411: case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256:
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410TC26A256, keys.m_SigningPrivateKey, signingPublicKey); case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST:
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410CryptoProA, keys.m_SigningPrivateKey, signingPublicKey);
break; break;
case SIGNING_KEY_TYPE_GOSTR3410_2012_TC26_A_512_GOSTR3411: case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512_TEST:
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410TC26A512, keys.m_SigningPrivateKey, signingPublicKey); i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410TC26A512, keys.m_SigningPrivateKey, signingPublicKey);
break; break;
default: default:

11
Identity.h

@ -60,11 +60,14 @@ namespace data
const uint16_t SIGNING_KEY_TYPE_RSA_SHA384_3072 = 5; const uint16_t SIGNING_KEY_TYPE_RSA_SHA384_3072 = 5;
const uint16_t SIGNING_KEY_TYPE_RSA_SHA512_4096 = 6; const uint16_t SIGNING_KEY_TYPE_RSA_SHA512_4096 = 6;
const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 = 7; const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 = 7;
const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519ph = 8; // not implemented
// following signature type should never appear in netid=2 // following signature type should never appear in netid=2
const uint16_t SIGNING_KEY_TYPE_GOSTR3410_2001_CRYPTO_PRO_A_GOSTR3411 = 65280; // approved by FSB const uint16_t SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256 = 9;
const uint16_t SIGNING_KEY_TYPE_GOSTR3410_2012_TC26_A_256_GOSTR3411 = 65281; const uint16_t SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512 = 10; // approved by FSB
const uint16_t SIGNING_KEY_TYPE_GOSTR3410_2012_TC26_A_512_GOSTR3411 = 65282; // TODO: remove later
const uint16_t SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST = 65281;
const uint16_t SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512_TEST = 65282;
typedef uint16_t SigningKeyType; typedef uint16_t SigningKeyType;
typedef uint16_t CryptoKeyType; typedef uint16_t CryptoKeyType;

3
Makefile.linux

@ -55,15 +55,12 @@ else
endif endif
endif endif
IS_64 := $(shell $(CXX) -dumpmachine 2>&1 | $(GREP) -c "64")
ifeq ($(USE_AESNI),yes) ifeq ($(USE_AESNI),yes)
ifeq ($(IS_64),1)
#check if AES-NI is supported by CPU #check if AES-NI is supported by CPU
ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0) ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0)
CPU_FLAGS += -maes -DAESNI CPU_FLAGS += -maes -DAESNI
endif endif
endif endif
endif
ifeq ($(USE_AVX),yes) ifeq ($(USE_AVX),yes)
#check if AVX supported by CPU #check if AVX supported by CPU

59
SAM.cpp

@ -18,7 +18,7 @@ namespace client
SAMSocket::SAMSocket (SAMBridge& owner): SAMSocket::SAMSocket (SAMBridge& owner):
m_Owner (owner), m_Socket (m_Owner.GetService ()), m_Timer (m_Owner.GetService ()), m_Owner (owner), m_Socket (m_Owner.GetService ()), m_Timer (m_Owner.GetService ()),
m_BufferOffset (0), m_SocketType (eSAMSocketTypeUnknown), m_IsSilent (false), m_BufferOffset (0), m_SocketType (eSAMSocketTypeUnknown), m_IsSilent (false),
m_Stream (nullptr), m_Session (nullptr) m_IsAccepting (false), m_Stream (nullptr), m_Session (nullptr)
{ {
} }
@ -56,7 +56,7 @@ namespace client
if (m_Session) if (m_Session)
{ {
m_Session->DelSocket (shared_from_this ()); m_Session->DelSocket (shared_from_this ());
if (m_Session->localDestination) if (m_IsAccepting && m_Session->localDestination)
m_Session->localDestination->StopAcceptingStreams (); m_Session->localDestination->StopAcceptingStreams ();
} }
break; break;
@ -214,11 +214,11 @@ namespace client
if (!strcmp (m_Buffer, SAM_SESSION_CREATE)) if (!strcmp (m_Buffer, SAM_SESSION_CREATE))
ProcessSessionCreate (separator + 1, bytes_transferred - (separator - m_Buffer) - 1); ProcessSessionCreate (separator + 1, bytes_transferred - (separator - m_Buffer) - 1);
else if (!strcmp (m_Buffer, SAM_STREAM_CONNECT)) else if (!strcmp (m_Buffer, SAM_STREAM_CONNECT))
ProcessStreamConnect (separator + 1, bytes_transferred - (separator - m_Buffer) - 1); ProcessStreamConnect (separator + 1, bytes_transferred - (separator - m_Buffer) - 1, bytes_transferred - (eol - m_Buffer) - 1);
else if (!strcmp (m_Buffer, SAM_STREAM_ACCEPT)) else if (!strcmp (m_Buffer, SAM_STREAM_ACCEPT))
ProcessStreamAccept (separator + 1, bytes_transferred - (separator - m_Buffer) - 1); ProcessStreamAccept (separator + 1, bytes_transferred - (separator - m_Buffer) - 1);
else if (!strcmp (m_Buffer, SAM_DEST_GENERATE)) else if (!strcmp (m_Buffer, SAM_DEST_GENERATE))
ProcessDestGenerate (); ProcessDestGenerate (separator + 1, bytes_transferred - (separator - m_Buffer) - 1);
else if (!strcmp (m_Buffer, SAM_NAMING_LOOKUP)) else if (!strcmp (m_Buffer, SAM_NAMING_LOOKUP))
ProcessNamingLookup (separator + 1, bytes_transferred - (separator - m_Buffer) - 1); ProcessNamingLookup (separator + 1, bytes_transferred - (separator - m_Buffer) - 1);
else if (!strcmp (m_Buffer, SAM_DATAGRAM_SEND)) else if (!strcmp (m_Buffer, SAM_DATAGRAM_SEND))
@ -358,7 +358,7 @@ namespace client
SendMessageReply (m_Buffer, l2, false); SendMessageReply (m_Buffer, l2, false);
} }
void SAMSocket::ProcessStreamConnect (char * buf, size_t len) void SAMSocket::ProcessStreamConnect (char * buf, size_t len, size_t rem)
{ {
LogPrint (eLogDebug, "SAM: stream connect: ", buf); LogPrint (eLogDebug, "SAM: stream connect: ", buf);
std::map<std::string, std::string> params; std::map<std::string, std::string> params;
@ -371,9 +371,17 @@ namespace client
m_Session = m_Owner.FindSession (id); m_Session = m_Owner.FindSession (id);
if (m_Session) if (m_Session)
{ {
if (rem > 0) // handle follow on data
{
memmove (m_Buffer, buf + len + 1, rem); // buf is a pointer to m_Buffer's content
m_BufferOffset = rem;
}
else
m_BufferOffset = 0;
auto dest = std::make_shared<i2p::data::IdentityEx> (); auto dest = std::make_shared<i2p::data::IdentityEx> ();
size_t len = dest->FromBase64(destination); size_t l = dest->FromBase64(destination);
if (len > 0) if (l > 0)
{ {
context.GetAddressBook().InsertAddress(dest); context.GetAddressBook().InsertAddress(dest);
auto leaseSet = m_Session->localDestination->FindLeaseSet(dest->GetIdentHash()); auto leaseSet = m_Session->localDestination->FindLeaseSet(dest->GetIdentHash());
@ -398,7 +406,8 @@ namespace client
m_SocketType = eSAMSocketTypeStream; m_SocketType = eSAMSocketTypeStream;
m_Session->AddSocket (shared_from_this ()); m_Session->AddSocket (shared_from_this ());
m_Stream = m_Session->localDestination->CreateStream (remote); m_Stream = m_Session->localDestination->CreateStream (remote);
m_Stream->Send ((uint8_t *)m_Buffer, 0); // connect m_Stream->Send ((uint8_t *)m_Buffer, m_BufferOffset); // connect and send
m_BufferOffset = 0;
I2PReceive (); I2PReceive ();
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
} }
@ -429,7 +438,10 @@ namespace client
m_SocketType = eSAMSocketTypeAcceptor; m_SocketType = eSAMSocketTypeAcceptor;
m_Session->AddSocket (shared_from_this ()); m_Session->AddSocket (shared_from_this ());
if (!m_Session->localDestination->IsAcceptingStreams ()) if (!m_Session->localDestination->IsAcceptingStreams ())
{
m_IsAccepting = true;
m_Session->localDestination->AcceptOnce (std::bind (&SAMSocket::HandleI2PAccept, shared_from_this (), std::placeholders::_1)); m_Session->localDestination->AcceptOnce (std::bind (&SAMSocket::HandleI2PAccept, shared_from_this (), std::placeholders::_1));
}
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
} }
else else
@ -467,18 +479,26 @@ namespace client
return offset + size; return offset + size;
} }
void SAMSocket::ProcessDestGenerate () void SAMSocket::ProcessDestGenerate (char * buf, size_t len)
{ {
LogPrint (eLogDebug, "SAM: dest generate"); LogPrint (eLogDebug, "SAM: dest generate");
auto keys = i2p::data::PrivateKeys::CreateRandomKeys (); std::map<std::string, std::string> params;
ExtractParams (buf, params);
// extract signature type
i2p::data::SigningKeyType signatureType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1;
auto it = params.find (SAM_PARAM_SIGNATURE_TYPE);
if (it != params.end ())
// TODO: extract string values
signatureType = std::stoi(it->second);
auto keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType);
#ifdef _MSC_VER #ifdef _MSC_VER
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY,
keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ()); keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ());
#else #else
size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY,
keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ()); keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ());
#endif #endif
SendMessageReply (m_Buffer, len, false); SendMessageReply (m_Buffer, l, false);
} }
void SAMSocket::ProcessNamingLookup (char * buf, size_t len) void SAMSocket::ProcessNamingLookup (char * buf, size_t len)
@ -603,6 +623,8 @@ namespace client
{ {
if (m_Stream) if (m_Stream)
{ {
bytes_transferred += m_BufferOffset;
m_BufferOffset = 0;
auto s = shared_from_this (); auto s = shared_from_this ();
m_Stream->AsyncSend ((uint8_t *)m_Buffer, bytes_transferred, m_Stream->AsyncSend ((uint8_t *)m_Buffer, bytes_transferred,
[s](const boost::system::error_code& ecode) [s](const boost::system::error_code& ecode)
@ -690,6 +712,7 @@ namespace client
{ {
LogPrint (eLogDebug, "SAM: incoming I2P connection for session ", m_ID); LogPrint (eLogDebug, "SAM: incoming I2P connection for session ", m_ID);
m_SocketType = eSAMSocketTypeStream; m_SocketType = eSAMSocketTypeStream;
m_IsAccepting = false;
m_Stream = stream; m_Stream = stream;
context.GetAddressBook ().InsertAddress (stream->GetRemoteIdentity ()); context.GetAddressBook ().InsertAddress (stream->GetRemoteIdentity ());
auto session = m_Owner.FindSession (m_ID); auto session = m_Owner.FindSession (m_ID);
@ -699,6 +722,7 @@ namespace client
for (auto it: session->ListSockets ()) for (auto it: session->ListSockets ())
if (it->m_SocketType == eSAMSocketTypeAcceptor) if (it->m_SocketType == eSAMSocketTypeAcceptor)
{ {
it->m_IsAccepting = true;
session->localDestination->AcceptOnce (std::bind (&SAMSocket::HandleI2PAccept, it, std::placeholders::_1)); session->localDestination->AcceptOnce (std::bind (&SAMSocket::HandleI2PAccept, it, std::placeholders::_1));
break; break;
} }
@ -778,13 +802,14 @@ namespace client
void SAMSession::CloseStreams () void SAMSession::CloseStreams ()
{ {
std::vector<std::shared_ptr<SAMSocket> > socks;
{ {
std::lock_guard<std::mutex> lock(m_SocketsMutex); std::lock_guard<std::mutex> lock(m_SocketsMutex);
for (auto& sock : m_Sockets) { for (const auto& sock : m_Sockets) {
sock->CloseStream(); socks.push_back(sock);
} }
} }
// XXX: should this be done inside locked parts? for (auto & sock : socks ) sock->Terminate();
m_Sockets.clear(); m_Sockets.clear();
} }
@ -875,7 +900,7 @@ namespace client
if (destination != "") if (destination != "")
{ {
i2p::data::PrivateKeys keys; i2p::data::PrivateKeys keys;
keys.FromBase64 (destination); if (!keys.FromBase64 (destination)) return nullptr;
localDestination = i2p::client::context.CreateNewLocalDestination (keys, true, params); localDestination = i2p::client::context.CreateNewLocalDestination (keys, true, params);
} }
else // transient else // transient

11
SAM.h

@ -87,9 +87,9 @@ namespace client
void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; }; void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; };
SAMSocketType GetSocketType () const { return m_SocketType; }; SAMSocketType GetSocketType () const { return m_SocketType; };
void Terminate ();
private: private:
void Terminate ();
void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred);
@ -105,9 +105,9 @@ namespace client
void HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
void ProcessSessionCreate (char * buf, size_t len); void ProcessSessionCreate (char * buf, size_t len);
void ProcessStreamConnect (char * buf, size_t len); void ProcessStreamConnect (char * buf, size_t len, size_t rem);
void ProcessStreamAccept (char * buf, size_t len); void ProcessStreamAccept (char * buf, size_t len);
void ProcessDestGenerate (); void ProcessDestGenerate (char * buf, size_t len);
void ProcessNamingLookup (char * buf, size_t len); void ProcessNamingLookup (char * buf, size_t len);
void SendI2PError(const std::string & msg); void SendI2PError(const std::string & msg);
size_t ProcessDatagramSend (char * buf, size_t len, const char * data); // from SAM 1.0 size_t ProcessDatagramSend (char * buf, size_t len, const char * data); // from SAM 1.0
@ -131,6 +131,7 @@ namespace client
SAMSocketType m_SocketType; SAMSocketType m_SocketType;
std::string m_ID; // nickname std::string m_ID; // nickname
bool m_IsSilent; bool m_IsSilent;
bool m_IsAccepting; // for eSAMSocketTypeAcceptor only
std::shared_ptr<i2p::stream::Stream> m_Stream; std::shared_ptr<i2p::stream::Stream> m_Stream;
std::shared_ptr<SAMSession> m_Session; std::shared_ptr<SAMSession> m_Session;
}; };
@ -143,13 +144,13 @@ namespace client
std::mutex m_SocketsMutex; std::mutex m_SocketsMutex;
/** safely add a socket to this session */ /** safely add a socket to this session */
void AddSocket(std::shared_ptr<SAMSocket> sock) { void AddSocket(const std::shared_ptr<SAMSocket> & sock) {
std::lock_guard<std::mutex> lock(m_SocketsMutex); std::lock_guard<std::mutex> lock(m_SocketsMutex);
m_Sockets.push_back(sock); m_Sockets.push_back(sock);
} }
/** safely remove a socket from this session */ /** safely remove a socket from this session */
void DelSocket(std::shared_ptr<SAMSocket> sock) { void DelSocket(const std::shared_ptr<SAMSocket> & sock) {
std::lock_guard<std::mutex> lock(m_SocketsMutex); std::lock_guard<std::mutex> lock(m_SocketsMutex);
m_Sockets.remove(sock); m_Sockets.remove(sock);
} }

30
Signature.cpp

@ -168,14 +168,13 @@ namespace crypto
BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2 BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2
BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2 BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2
BN_CTX_start (ctx);
BIGNUM * t1 = p1.t, * t2 = p2.t; BIGNUM * t1 = p1.t, * t2 = p2.t;
if (!t1) { t1 = BN_new (); BN_mul (t1, p1.x, p1.y, ctx); } if (!t1) { t1 = BN_CTX_get (ctx); BN_mul (t1, p1.x, p1.y, ctx); }
if (!t2) { t2 = BN_new (); BN_mul (t2, p2.x, p2.y, ctx); } if (!t2) { t2 = BN_CTX_get (ctx); BN_mul (t2, p2.x, p2.y, ctx); }
BN_mul (t3, t1, t2, ctx); BN_mul (t3, t1, t2, ctx);
BN_mul (t3, t3, d, ctx); // C = d*t1*t2 BN_mul (t3, t3, d, ctx); // C = d*t1*t2
if (!p1.t) BN_free (t1);
if (!p2.t) BN_free (t2);
if (p1.z) if (p1.z)
{ {
@ -192,7 +191,6 @@ namespace crypto
BN_one (z3); // D = 1 BN_one (z3); // D = 1
} }
BN_CTX_start (ctx);
BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx); BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx);
BN_add (E, p1.x, p1.y); BN_add (E, p1.x, p1.y);
BN_add (F, p2.x, p2.y); BN_add (F, p2.x, p2.y);
@ -213,9 +211,10 @@ namespace crypto
return EDDSAPoint {x3, y3, z3, t3}; return EDDSAPoint {x3, y3, z3, t3};
} }
EDDSAPoint Double (const EDDSAPoint& p, BN_CTX * ctx) const void Double (EDDSAPoint& p, BN_CTX * ctx) const
{ {
BIGNUM * x2 = BN_new (), * y2 = BN_new (), * z2 = BN_new (), * t2 = BN_new (); BN_CTX_start (ctx);
BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * z2 = BN_CTX_get (ctx), * t2 = BN_CTX_get (ctx);
BN_sqr (x2, p.x, ctx); // x2 = A = x^2 BN_sqr (x2, p.x, ctx); // x2 = A = x^2
BN_sqr (y2, p.y, ctx); // y2 = B = y^2 BN_sqr (y2, p.y, ctx); // y2 = B = y^2
@ -232,7 +231,6 @@ namespace crypto
else else
BN_one (z2); // z2 = 1 BN_one (z2); // z2 = 1
BN_CTX_start (ctx);
BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx); BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx);
// E = (x+y)*(x+y)-A-B = x^2+y^2+2xy-A-B = 2xy // E = (x+y)*(x+y)-A-B = x^2+y^2+2xy-A-B = 2xy
BN_mul (E, p.x, p.y, ctx); BN_mul (E, p.x, p.y, ctx);
@ -241,14 +239,14 @@ namespace crypto
BN_add (G, z2, t2); // G = D + C BN_add (G, z2, t2); // G = D + C
BN_add (H, y2, x2); // H = B + A BN_add (H, y2, x2); // H = B + A
BN_mod_mul (x2, E, F, q, ctx); // x2 = E*F BN_mod_mul (p.x, E, F, q, ctx); // x2 = E*F
BN_mod_mul (y2, G, H, q, ctx); // y2 = G*H BN_mod_mul (p.y, G, H, q, ctx); // y2 = G*H
BN_mod_mul (z2, F, G, q, ctx); // z2 = F*G if (!p.z) p.z = BN_new ();
BN_mod_mul (t2, E, H, q, ctx); // t2 = E*H BN_mod_mul (p.z, F, G, q, ctx); // z2 = F*G
if (!p.t) p.t = BN_new ();
BN_mod_mul (p.t, E, H, q, ctx); // t2 = E*H
BN_CTX_end (ctx); BN_CTX_end (ctx);
return EDDSAPoint {x2, y2, z2, t2};
} }
EDDSAPoint Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const EDDSAPoint Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const
@ -261,7 +259,7 @@ namespace crypto
int bitCount = BN_num_bits (e); int bitCount = BN_num_bits (e);
for (int i = bitCount - 1; i >= 0; i--) for (int i = bitCount - 1; i >= 0; i--)
{ {
res = Double (res, ctx); Double (res, ctx);
if (BN_is_bit_set (e, i)) res = Sum (res, p, ctx); if (BN_is_bit_set (e, i)) res = Sum (res, p, ctx);
} }
} }

30
Signature.h

@ -444,32 +444,22 @@ namespace crypto
} }
// ГОСТ Р 34.11 // ГОСТ Р 34.11
struct GOSTR3411_2001_Hash struct GOSTR3411_256_Hash
{ {
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{ {
SHA256 (buf, len, digest); // TODO: implement GOST R 34.11 - 2001 GOSTR3411_2012_256 (buf, len, digest);
}
enum { hashLen = 32 };
};
struct GOSTR3411_2012_256_Hash
{
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{
SHA256 (buf, len, digest); // TODO: implement GOST R 34.11 - 2012
} }
enum { hashLen = 32 }; enum { hashLen = 32 };
}; };
struct GOSTR3411_2012_512_Hash struct GOSTR3411_512_Hash
{ {
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{ {
SHA512 (buf, len, digest); // TODO: implement GOST R 34.11 - 2012 GOSTR3411_2012_512 (buf, len, digest);
} }
enum { hashLen = 64 }; enum { hashLen = 64 };
@ -566,12 +556,10 @@ namespace crypto
BN_free (x); BN_free (y); BN_free (x); BN_free (y);
} }
typedef GOSTR3410Verifier<GOSTR3411_2001_Hash> GOSTR3410_2001_Verifier; typedef GOSTR3410Verifier<GOSTR3411_256_Hash> GOSTR3410_256_Verifier;
typedef GOSTR3410Signer<GOSTR3411_2001_Hash> GOSTR3410_2001_Signer; typedef GOSTR3410Signer<GOSTR3411_256_Hash> GOSTR3410_256_Signer;
typedef GOSTR3410Verifier<GOSTR3411_2012_256_Hash> GOSTR3410_2012_256_Verifier; typedef GOSTR3410Verifier<GOSTR3411_512_Hash> GOSTR3410_512_Verifier;
typedef GOSTR3410Signer<GOSTR3411_2012_256_Hash> GOSTR3410_2012_256_Signer; typedef GOSTR3410Signer<GOSTR3411_512_Hash> GOSTR3410_512_Signer;
typedef GOSTR3410Verifier<GOSTR3411_2012_512_Hash> GOSTR3410_2012_512_Verifier;
typedef GOSTR3410Signer<GOSTR3411_2012_512_Hash> GOSTR3410_2012_512_Signer;
} }
} }

14
Streaming.cpp

@ -1091,16 +1091,18 @@ namespace stream
} }
else // we must save old acceptor and set it back else // we must save old acceptor and set it back
{ {
auto oldAcceptor = m_Acceptor; m_Acceptor = std::bind (&StreamingDestination::AcceptOnceAcceptor, this,
m_Acceptor = [acceptor, oldAcceptor, this](std::shared_ptr<Stream> stream) std::placeholders::_1, acceptor, m_Acceptor);
{
acceptor (stream);
m_Acceptor = oldAcceptor;
};
} }
}); });
} }
void StreamingDestination::AcceptOnceAcceptor (std::shared_ptr<Stream> stream, Acceptor acceptor, Acceptor prev)
{
m_Acceptor = prev;
acceptor (stream);
}
void StreamingDestination::HandlePendingIncomingTimer (const boost::system::error_code& ecode) void StreamingDestination::HandlePendingIncomingTimer (const boost::system::error_code& ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)

4
Streaming.h

@ -280,7 +280,9 @@ namespace stream
void DeletePacket (Packet * p) { if (p) m_PacketsPool.Release (p); }; void DeletePacket (Packet * p) { if (p) m_PacketsPool.Release (p); };
private: private:
void AcceptOnceAcceptor (std::shared_ptr<Stream> stream, Acceptor acceptor, Acceptor prev);
void HandleNextPacket (Packet * packet); void HandleNextPacket (Packet * packet);
std::shared_ptr<Stream> CreateNewIncomingStream (); std::shared_ptr<Stream> CreateNewIncomingStream ();
void HandlePendingIncomingTimer (const boost::system::error_code& ecode); void HandlePendingIncomingTimer (const boost::system::error_code& ecode);

2
api.cpp

@ -19,7 +19,7 @@ namespace api
void InitI2P (int argc, char* argv[], const char * appName) void InitI2P (int argc, char* argv[], const char * appName)
{ {
i2p::config::Init (); i2p::config::Init ();
i2p::config::ParseCmdline (argc, argv); i2p::config::ParseCmdline (argc, argv, true); // ignore unknown options and help
i2p::config::Finalize (); i2p::config::Finalize ();
std::string datadir; i2p::config::GetOption("datadir", datadir); std::string datadir; i2p::config::GetOption("datadir", datadir);

1
appveyor.yml

@ -19,6 +19,7 @@ environment:
install: install:
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc" - c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc"
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu" - c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu"
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu" - c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu"
- if "%MSYSTEM%" == "MINGW64" ( - if "%MSYSTEM%" == "MINGW64" (

3
build/.gitignore vendored

@ -8,3 +8,6 @@
/CPackConfig.cmake /CPackConfig.cmake
/CPackSourceConfig.cmake /CPackSourceConfig.cmake
/install_manifest.txt /install_manifest.txt
# windows build script
i2pd*.zip
build*.log

62
build/build_mingw.cmd

@ -0,0 +1,62 @@
@echo off
setlocal enableextensions enabledelayedexpansion
title Building i2pd
REM Copyright (c) 2013-2017, The PurpleI2P Project
REM This file is part of Purple i2pd project and licensed under BSD3
REM See full license text in LICENSE file at top of project tree
REM To use that script, you must have installed in your MSYS installation theese packages:
REM Base: git make zip
REM x86_64: mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-gcc
REM i686: mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-gcc
REM setting up variables for MSYS
REM Note: if you installed MSYS64 to different path, edit WD variable (only C:\msys64 needed to edit)!
set "WD=C:\msys64\usr\bin\"
set MSYS2_PATH_TYPE=inherit
set CHERE_INVOKING=enabled_from_arguments
set MSYSTEM=MSYS
REM detecting number of processors and subtract 1.
set /a threads=%NUMBER_OF_PROCESSORS%-1
REM we must work in root of repo
cd ..
echo Receiving latest commit and cleaning up...
"%WD%bash" -lc "git pull && make clean" > build/build_git.log 2>&1
echo.
REM set to variable current commit hash
FOR /F "usebackq" %%a IN (`%WD%bash -lc 'git describe --tags'`) DO (
set tag=%%a
)
REM starting building
set MSYSTEM=MINGW32
set bitness=32
call :BUILDING
echo.
set MSYSTEM=MINGW64
set bitness=64
call :BUILDING
echo.
echo Build complete...
pause
exit /b 0
:BUILDING
echo Building i2pd %tag% for win%bitness%:
echo Build AVX+AESNI...
"%WD%bash" -lc "make USE_UPNP=yes USE_AVX=1 USE_AESNI=1 -j%threads% && zip -9 build/i2pd_%tag%_win%bitness%_mingw_avx_aesni.zip i2pd.exe && make clean" > build/build_win%bitness%_avx_aesni.log 2>&1
echo Build AVX...
"%WD%bash" -lc "make USE_UPNP=yes USE_AVX=1 -j%threads% && zip -9 build/i2pd_%tag%_win%bitness%_mingw_avx.zip i2pd.exe && make clean" > build/build_win%bitness%_avx.log 2>&1
echo Build AESNI...
"%WD%bash" -lc "make USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip i2pd.exe && make clean" > build/build_win%bitness%_aesni.log 2>&1
echo Build without extensions...
"%WD%bash" -lc "make USE_UPNP=yes -j%threads% && zip -9 build/i2pd_%tag%_win%bitness%_mingw.zip i2pd.exe && make clean" > build/build_win%bitness%.log 2>&1
:EOF

2
contrib/.gitignore vendored

@ -1,2 +0,0 @@
i2pd*.zip
build*.log

25
contrib/build_mingw.cmd

@ -1,25 +0,0 @@
@echo off
setlocal
title Building i2pd
set "WD=C:\msys64\usr\bin\"
set MSYS2_PATH_TYPE=inherit
set CHERE_INVOKING=enabled_from_arguments
set MSYSCON=
echo Building i2pd for win32. Press Enter after the end of compilation...
set MSYSTEM=MINGW32
set CONTITLE=MinGW x32
start "%CONTITLE%" /WAIT "%WD%bash" --login build_mingw.sh
pause > nul
echo Building i2pd for win64. Press Enter after the end of compilation...
set MSYSTEM=MINGW64
set CONTITLE=MinGW x64
start "%CONTITLE%" /WAIT "%WD%bash" --login build_mingw.sh
pause > nul
echo Build complete...
pause
exit /b 0

88
contrib/build_mingw.sh

@ -1,88 +0,0 @@
#!/bin/sh
# Определяем архитектуру.
if [ $MSYSTEM == MINGW64 ]; then
export arch="win64"
elif [ $MSYSTEM == MINGW32 ]; then
export arch="win32"
else
echo "Не могу понять, какая у вас архитектура, используемая для сборки.";
echo "Вы точно запустили скрипт в оболочке MSYS2 MinGW [64/32]-bit ?";
echo "Обычно её можно запустить выполнив c:\msys64\mingw64.exe или c:\msys64\mingw32.exe";
exit 1;
fi;
# Задаём переменной contrib текущий путь и переходим на уровень выше.
export contrib=$PWD
cd ..
# Очистка от предыдущей сборки (на всякий случай =) ).
make clean >> /dev/null
# Обновляем репозиторий, и получаем хеш последнего коммита.
echo "Получаем обновления из репозитория.";
git pull
if [ "$?" != 0 ]; then
echo "Не удалось обновить локальный репозиторий.";
echo "Вы точно запустили скрипт в папке репозитория?";
exit 1;
fi;
export commit=$(git rev-parse --verify HEAD | cut -c -7)
if [ -z commit ]; then
echo "Не удалось получить хеш последнего коммита.";
echo "Вы точно запустили скрипт в папке репозитория?";
exit 1;
fi;
# Получаем версию приложения
export version=$(grep -E "I2PD_VERSION_(MAJOR|MINOR|MICRO)\ " version.h | grep -oE '[^ ]+$' | tr '\n' '.'|head -c -1)
# Получаем количество ядер, и уменьшаем количество потоков на 1 от количества ядер (если их больше чем 1).
if [ $NUMBER_OF_PROCESSORS -ge 2 ]; then
export threads=$(( $NUMBER_OF_PROCESSORS - 1 ))
else
export threads=$NUMBER_OF_PROCESSORS
fi;
echo "Собираем i2pd ${version} (коммит ${commit}) для ${arch}.";
# Собираем приложение с разными параметрами, и архивируем в zip архивы.
echo "Сборка AVX+AESNI";
make USE_UPNP=yes USE_AVX=1 USE_AESNI=1 -j ${threads} > ${contrib}/build_${arch}_avx_aesni.log 2>&1
if [ "$?" != 0 ]; then
echo "Сборка не удалась. Смотрите в build_avx_aesni.log";
exit 1;
fi;
zip -9 ${contrib}/i2pd_${version}_${commit}_${arch}_mingw_avx_aesni.zip i2pd.exe >> /dev/null
make clean >> /dev/null
echo "Сборка AVX";
make USE_UPNP=yes USE_AVX=1 -j ${threads} > ${contrib}/build_${arch}_avx.log 2>&1
if [ "$?" != 0 ]; then
echo "Сборка не удалась. Смотрите в build_avx.log.";
exit 1;
fi;
zip -9 ${contrib}/i2pd_${version}_${commit}_${arch}_mingw_avx.zip i2pd.exe >> /dev/null
make clean >> /dev/null
echo "Сборка AESNI";
make USE_UPNP=yes USE_AESNI=1 -j ${threads} > ${contrib}/build_${arch}_aesni.log 2>&1
if [ "$?" != 0 ]; then
echo "Сборка не удалась. Смотрите в build_aesni.log";
exit 1;
fi;
zip -9 ${contrib}/i2pd_${version}_${commit}_${arch}_mingw_aesni.zip i2pd.exe >> /dev/null
make clean >> /dev/null
echo "Сборка без дополнительных инструкций";
make USE_UPNP=yes -j ${threads} > ${contrib}/build_${arch}.log 2>&1
if [ "$?" != 0 ]; then
echo "Сборка не удалась. Смотрите в build.log";
exit 1;
fi;
zip -9 ${contrib}/i2pd_${version}_${commit}_${arch}_mingw.zip i2pd.exe >> /dev/null
make clean >> /dev/null
echo "Сборка i2pd ${version} для ${arch} завершена.";
exit 0;

9
tests/Makefile

@ -1,7 +1,6 @@
CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
TESTS = test-http-url test-http-req test-http-res test-http-url_decode \ TESTS = test-gost test-gost-sig test-base-64
test-http-merge_chunked test-base-64
all: $(TESTS) run all: $(TESTS) run
@ -11,6 +10,12 @@ test-http-%: ../HTTP.cpp test-http-%.cpp
test-base-%: ../Base.cpp test-base-%.cpp test-base-%: ../Base.cpp test-base-%.cpp
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^
test-gost: ../Gost.cpp ../I2PEndian.cpp test-gost.cpp
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto
test-gost-sig: ../Gost.cpp ../I2PEndian.cpp ../Signature.cpp ../Crypto.cpp ../Log.cpp test-gost-sig.cpp
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
run: $(TESTS) run: $(TESTS)
@for TEST in $(TESTS); do ./$$TEST ; done @for TEST in $(TESTS); do ./$$TEST ; done

35
tests/test-gost-sig.cpp

@ -0,0 +1,35 @@
#include <cassert>
#include <inttypes.h>
#include <string.h>
#include "../Gost.h"
#include "../Signature.h"
const uint8_t example2[72] =
{
0xfb,0xe2,0xe5,0xf0,0xee,0xe3,0xc8,0x20,0xfb,0xea,0xfa,0xeb,0xef,0x20,0xff,0xfb,
0xf0,0xe1,0xe0,0xf0,0xf5,0x20,0xe0,0xed,0x20,0xe8,0xec,0xe0,0xeb,0xe5,0xf0,0xf2,
0xf1,0x20,0xff,0xf0,0xee,0xec,0x20,0xf1,0x20,0xfa,0xf2,0xfe,0xe5,0xe2,0x20,0x2c,
0xe8,0xf6,0xf3,0xed,0xe2,0x20,0xe8,0xe6,0xee,0xe1,0xe8,0xf0,0xf2,0xd1,0x20,0x2c,
0xe8,0xf0,0xf2,0xe5,0xe2,0x20,0xe5,0xd1
};
int main ()
{
uint8_t priv[64], pub[128], signature[128];
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410TC26A512, priv, pub);
i2p::crypto::GOSTR3410_512_Signer signer (i2p::crypto::eGOSTR3410TC26A512, priv);
signer.Sign (example2, 72, signature);
i2p::crypto::GOSTR3410_512_Verifier verifier (i2p::crypto::eGOSTR3410TC26A512, pub);
assert (verifier.Verify (example2, 72, signature));
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410CryptoProA, priv, pub);
i2p::crypto::GOSTR3410_256_Signer signer1 (i2p::crypto::eGOSTR3410CryptoProA, priv);
signer1.Sign (example2, 72, signature);
i2p::crypto::GOSTR3410_256_Verifier verifier1 (i2p::crypto::eGOSTR3410CryptoProA, pub);
assert (verifier1.Verify (example2, 72, signature));
}

69
tests/test-gost.cpp

@ -0,0 +1,69 @@
#include <cassert>
#include <inttypes.h>
#include <string.h>
#include "../Gost.h"
const uint8_t example1[63] =
{
0x32,0x31,0x30,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x39,0x38,0x37,
0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,
0x30,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x39,0x38,0x37,0x36,0x35,
0x34,0x33,0x32,0x31,0x30,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30
};
const uint8_t example2[72] =
{
0xfb,0xe2,0xe5,0xf0,0xee,0xe3,0xc8,0x20,0xfb,0xea,0xfa,0xeb,0xef,0x20,0xff,0xfb,
0xf0,0xe1,0xe0,0xf0,0xf5,0x20,0xe0,0xed,0x20,0xe8,0xec,0xe0,0xeb,0xe5,0xf0,0xf2,
0xf1,0x20,0xff,0xf0,0xee,0xec,0x20,0xf1,0x20,0xfa,0xf2,0xfe,0xe5,0xe2,0x20,0x2c,
0xe8,0xf6,0xf3,0xed,0xe2,0x20,0xe8,0xe6,0xee,0xe1,0xe8,0xf0,0xf2,0xd1,0x20,0x2c,
0xe8,0xf0,0xf2,0xe5,0xe2,0x20,0xe5,0xd1
};
const uint8_t example1_hash_512[64] =
{
0x48,0x6f,0x64,0xc1,0x91,0x78,0x79,0x41,0x7f,0xef,0x08,0x2b,0x33,0x81,0xa4,0xe2,
0x11,0xc3,0x24,0xf0,0x74,0x65,0x4c,0x38,0x82,0x3a,0x7b,0x76,0xf8,0x30,0xad,0x00,
0xfa,0x1f,0xba,0xe4,0x2b,0x12,0x85,0xc0,0x35,0x2f,0x22,0x75,0x24,0xbc,0x9a,0xb1,
0x62,0x54,0x28,0x8d,0xd6,0x86,0x3d,0xcc,0xd5,0xb9,0xf5,0x4a,0x1a,0xd0,0x54,0x1b
};
const uint8_t example1_hash_256[32] =
{
0x00,0x55,0x7b,0xe5,0xe5,0x84,0xfd,0x52,0xa4,0x49,0xb1,0x6b,0x02,0x51,0xd0,0x5d,
0x27,0xf9,0x4a,0xb7,0x6c,0xba,0xa6,0xda,0x89,0x0b,0x59,0xd8,0xef,0x1e,0x15,0x9d
};
const uint8_t example2_hash_512[64] =
{
0x28,0xfb,0xc9,0xba,0xda,0x03,0x3b,0x14,0x60,0x64,0x2b,0xdc,0xdd,0xb9,0x0c,0x3f,
0xb3,0xe5,0x6c,0x49,0x7c,0xcd,0x0f,0x62,0xb8,0xa2,0xad,0x49,0x35,0xe8,0x5f,0x03,
0x76,0x13,0x96,0x6d,0xe4,0xee,0x00,0x53,0x1a,0xe6,0x0f,0x3b,0x5a,0x47,0xf8,0xda,
0xe0,0x69,0x15,0xd5,0xf2,0xf1,0x94,0x99,0x6f,0xca,0xbf,0x26,0x22,0xe6,0x88,0x1e
};
const uint8_t example2_hash_256[32] =
{
0x50,0x8f,0x7e,0x55,0x3c,0x06,0x50,0x1d,0x74,0x9a,0x66,0xfc,0x28,0xc6,0xca,0xc0,
0xb0,0x05,0x74,0x6d,0x97,0x53,0x7f,0xa8,0x5d,0x9e,0x40,0x90,0x4e,0xfe,0xd2,0x9d
};
int main ()
{
uint8_t digest[64];
i2p::crypto::GOSTR3411_2012_512 (example1, 63, digest);
assert(memcmp (digest, example1_hash_512, 64) == 0);
i2p::crypto::GOSTR3411_2012_256 (example1, 63, digest);
assert(memcmp (digest, example1_hash_256, 32) == 0);
i2p::crypto::GOSTR3411_2012_512 (example2, 72, digest);
assert(memcmp (digest, example2_hash_512, 64) == 0);
i2p::crypto::GOSTR3411_2012_256 (example2, 72, digest);
assert(memcmp (digest, example2_hash_256, 32) == 0);
}
Loading…
Cancel
Save