identity.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // acetone, 2024
  2. // I hate copyright of any kind. This is a public domain.
  3. // Original source: https://notabug.org/acetone/samty
  4. #include "identity.h"
  5. #include "byteorder.h"
  6. #include "codec/base32_rfc4648.hpp"
  7. #include "codec/base64_i2p.hpp"
  8. #include "sha256.h"
  9. #include <algorithm>
  10. #include <vector>
  11. namespace Samty {
  12. constexpr short IDENTITY_ENCRYPTION_PUBLIC_SIZE = 256;
  13. constexpr short IDENTITY_SIGNING_PUBLIC_SIZE = 128;
  14. constexpr short IDENTITY_CERT_SIZE = 3;
  15. constexpr short MINIMAL_IDENTITY_SIZE = IDENTITY_ENCRYPTION_PUBLIC_SIZE + IDENTITY_SIGNING_PUBLIC_SIZE + IDENTITY_CERT_SIZE;
  16. Identity::Identity() {}
  17. bool Identity::init(const std::string &base64I2pStyled, bool generateB33)
  18. {
  19. std::vector<uint8_t> rawDecoded;
  20. try {
  21. rawDecoded = cppcodec_samty::base64_i2p::decode(base64I2pStyled);
  22. } catch (...) {
  23. m_errorString = "Incorrect base64 data";
  24. return false;
  25. }
  26. if (rawDecoded.size() < MINIMAL_IDENTITY_SIZE)
  27. {
  28. m_errorString = "Data too small";
  29. return false;
  30. }
  31. auto certPart (rawDecoded);
  32. certPart.erase(certPart.begin(), certPart.begin()+IDENTITY_ENCRYPTION_PUBLIC_SIZE+IDENTITY_SIGNING_PUBLIC_SIZE);
  33. certPart.erase(certPart.begin()+IDENTITY_CERT_SIZE, certPart.end());
  34. uint8_t type = *reinterpret_cast<const uint8_t*>(certPart.data());
  35. m_certificateType = static_cast<CertificateType>(type);
  36. if (m_certificateType != CertificateType::Key)
  37. {
  38. m_errorString = "Certificate type is invalid (key supported only = 5, received " + std::to_string(type) + ")";
  39. return false;
  40. }
  41. uint16_t certPayloadSize = *reinterpret_cast<const uint16_t*>(certPart.data()+1);
  42. ByteOrder::reverse(reinterpret_cast<uint8_t*>(&certPayloadSize), 2);
  43. if (rawDecoded.size() < IDENTITY_ENCRYPTION_PUBLIC_SIZE+IDENTITY_SIGNING_PUBLIC_SIZE+IDENTITY_CERT_SIZE+certPayloadSize)
  44. {
  45. m_errorString = "Certificate payload size out of range";
  46. return false;
  47. }
  48. if (certPayloadSize < 4)
  49. {
  50. m_errorString = "Certificate payload size is unsupported (4 bytes or more required for key type)";
  51. return false;
  52. }
  53. auto certPayloadPart (rawDecoded);
  54. certPayloadPart.erase(certPayloadPart.begin(), certPayloadPart.begin()+IDENTITY_ENCRYPTION_PUBLIC_SIZE+IDENTITY_SIGNING_PUBLIC_SIZE+IDENTITY_CERT_SIZE);
  55. certPayloadPart.erase(certPayloadPart.begin()+certPayloadSize, certPayloadPart.end());
  56. uint16_t signTypeId = *reinterpret_cast<const uint16_t*>(certPayloadPart.data());
  57. ByteOrder::reverse(reinterpret_cast<uint8_t*>(&signTypeId), 2);
  58. if (signTypeId > MAX_SIGNATURE_TYPE_ID)
  59. {
  60. m_errorString = "Invalid signature type";
  61. return false;
  62. }
  63. m_signatureType = static_cast<SignatureType>(signTypeId);
  64. auto publicPart (rawDecoded);
  65. publicPart.erase(publicPart.begin()+IDENTITY_ENCRYPTION_PUBLIC_SIZE+IDENTITY_SIGNING_PUBLIC_SIZE+IDENTITY_CERT_SIZE+certPayloadSize, publicPart.end());
  66. SHA256 sha;
  67. sha.update(publicPart.data(), publicPart.size());
  68. const auto digest = sha.digest();
  69. m_destB32 = cppcodec_samty::base32_rfc4648::encode( digest.data(), digest.size() );
  70. m_pubBase64 = cppcodec_samty::base64_i2p::encode(publicPart);
  71. m_fullBase64 = base64I2pStyled;
  72. if (not generateB33) return true;
  73. std::vector<uint8_t> signPublicKey = rawDecoded;
  74. signPublicKey.erase(signPublicKey.begin(), signPublicKey.begin()+IDENTITY_ENCRYPTION_PUBLIC_SIZE);
  75. signPublicKey.erase(signPublicKey.begin()+IDENTITY_SIGNING_PUBLIC_SIZE, signPublicKey.end());
  76. signPublicKey.erase(signPublicKey.begin(), signPublicKey.end()-KEY_LENGTH[signTypeId]); // Leveling to the right
  77. if (signPublicKey.size () != 32) // assume 25519
  78. {
  79. m_errorString = "B33 address requested, but key type does not match";
  80. return false;
  81. }
  82. // https://github.com/PurpleI2P/i2pd/blob/2c19da9aa784ad042c3893e98718068b6556bc34/libi2pd/Blinding.cpp#L198
  83. std::vector<uint8_t> addr(35);
  84. uint8_t flags = 0;
  85. addr[0] = flags;
  86. addr[1] = signTypeId;
  87. addr[2] = signTypeId == 7 ? 11 : signTypeId;
  88. std::copy (signPublicKey.begin(), signPublicKey.end(), addr.begin()+3);
  89. uint32_t checksum = ByteOrder::crc32_16bytes(addr.data()+3, signPublicKey.size());
  90. addr[0] ^= checksum;
  91. addr[1] ^= (checksum >> 8);
  92. addr[2] ^= (checksum >> 16);
  93. m_destB33 = cppcodec_samty::base32_rfc4648::encode(addr);
  94. return true;
  95. }
  96. } // namespace