123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- // acetone, 2024
- // I hate copyright of any kind. This is a public domain.
- // Original source: https://notabug.org/acetone/samty
- #include "identity.h"
- #include "byteorder.h"
- #include "codec/base32_rfc4648.hpp"
- #include "codec/base64_i2p.hpp"
- #include "sha256.h"
- #include <algorithm>
- #include <vector>
- namespace Samty {
- constexpr short IDENTITY_ENCRYPTION_PUBLIC_SIZE = 256;
- constexpr short IDENTITY_SIGNING_PUBLIC_SIZE = 128;
- constexpr short IDENTITY_CERT_SIZE = 3;
- constexpr short MINIMAL_IDENTITY_SIZE = IDENTITY_ENCRYPTION_PUBLIC_SIZE + IDENTITY_SIGNING_PUBLIC_SIZE + IDENTITY_CERT_SIZE;
- Identity::Identity() {}
- bool Identity::init(const std::string &base64I2pStyled, bool generateB33)
- {
- std::vector<uint8_t> rawDecoded;
- try {
- rawDecoded = cppcodec_samty::base64_i2p::decode(base64I2pStyled);
- } catch (...) {
- m_errorString = "Incorrect base64 data";
- return false;
- }
- if (rawDecoded.size() < MINIMAL_IDENTITY_SIZE)
- {
- m_errorString = "Data too small";
- return false;
- }
- auto certPart (rawDecoded);
- certPart.erase(certPart.begin(), certPart.begin()+IDENTITY_ENCRYPTION_PUBLIC_SIZE+IDENTITY_SIGNING_PUBLIC_SIZE);
- certPart.erase(certPart.begin()+IDENTITY_CERT_SIZE, certPart.end());
- uint8_t type = *reinterpret_cast<const uint8_t*>(certPart.data());
- m_certificateType = static_cast<CertificateType>(type);
- if (m_certificateType != CertificateType::Key)
- {
- m_errorString = "Certificate type is invalid (key supported only = 5, received " + std::to_string(type) + ")";
- return false;
- }
- uint16_t certPayloadSize = *reinterpret_cast<const uint16_t*>(certPart.data()+1);
- ByteOrder::reverse(reinterpret_cast<uint8_t*>(&certPayloadSize), 2);
- if (rawDecoded.size() < IDENTITY_ENCRYPTION_PUBLIC_SIZE+IDENTITY_SIGNING_PUBLIC_SIZE+IDENTITY_CERT_SIZE+certPayloadSize)
- {
- m_errorString = "Certificate payload size out of range";
- return false;
- }
- if (certPayloadSize < 4)
- {
- m_errorString = "Certificate payload size is unsupported (4 bytes or more required for key type)";
- return false;
- }
- auto certPayloadPart (rawDecoded);
- certPayloadPart.erase(certPayloadPart.begin(), certPayloadPart.begin()+IDENTITY_ENCRYPTION_PUBLIC_SIZE+IDENTITY_SIGNING_PUBLIC_SIZE+IDENTITY_CERT_SIZE);
- certPayloadPart.erase(certPayloadPart.begin()+certPayloadSize, certPayloadPart.end());
- uint16_t signTypeId = *reinterpret_cast<const uint16_t*>(certPayloadPart.data());
- ByteOrder::reverse(reinterpret_cast<uint8_t*>(&signTypeId), 2);
- if (signTypeId > MAX_SIGNATURE_TYPE_ID)
- {
- m_errorString = "Invalid signature type";
- return false;
- }
- m_signatureType = static_cast<SignatureType>(signTypeId);
- auto publicPart (rawDecoded);
- publicPart.erase(publicPart.begin()+IDENTITY_ENCRYPTION_PUBLIC_SIZE+IDENTITY_SIGNING_PUBLIC_SIZE+IDENTITY_CERT_SIZE+certPayloadSize, publicPart.end());
- SHA256 sha;
- sha.update(publicPart.data(), publicPart.size());
- const auto digest = sha.digest();
- m_destB32 = cppcodec_samty::base32_rfc4648::encode( digest.data(), digest.size() );
- m_pubBase64 = cppcodec_samty::base64_i2p::encode(publicPart);
- m_fullBase64 = base64I2pStyled;
- if (not generateB33) return true;
- std::vector<uint8_t> signPublicKey = rawDecoded;
- signPublicKey.erase(signPublicKey.begin(), signPublicKey.begin()+IDENTITY_ENCRYPTION_PUBLIC_SIZE);
- signPublicKey.erase(signPublicKey.begin()+IDENTITY_SIGNING_PUBLIC_SIZE, signPublicKey.end());
- signPublicKey.erase(signPublicKey.begin(), signPublicKey.end()-KEY_LENGTH[signTypeId]); // Leveling to the right
- if (signPublicKey.size () != 32) // assume 25519
- {
- m_errorString = "B33 address requested, but key type does not match";
- return false;
- }
- // https://github.com/PurpleI2P/i2pd/blob/2c19da9aa784ad042c3893e98718068b6556bc34/libi2pd/Blinding.cpp#L198
- std::vector<uint8_t> addr(35);
- uint8_t flags = 0;
- addr[0] = flags;
- addr[1] = signTypeId;
- addr[2] = signTypeId == 7 ? 11 : signTypeId;
- std::copy (signPublicKey.begin(), signPublicKey.end(), addr.begin()+3);
- uint32_t checksum = ByteOrder::crc32_16bytes(addr.data()+3, signPublicKey.size());
- addr[0] ^= checksum;
- addr[1] ^= (checksum >> 8);
- addr[2] ^= (checksum >> 16);
- m_destB33 = cppcodec_samty::base32_rfc4648::encode(addr);
- return true;
- }
- } // namespace
|