加载在 JSBN 中创建的 RSA public 密钥,然后加密消息

Load RSA public key created in JSBN, then encrypt a message

我正在尝试使用 JSBN 在 JavaScript 中创建一个 RSA 密钥对,并将 public 密钥传输到 Crypto++。然后,我尝试用 Crypto++ 加密消息并将其发送回 JavaScript 并解密。

但是我在这方面比较陌生,所以我认为我做错了什么(数据没有被解密 ofc)

任何帮助将不胜感激:D

这是我的 cpp 代码

Integer n(nStr->c_str()),
e("0x10001");

RSA::PublicKey pubKey;
pubKey.Initialize(n, e);

AutoSeededRandomPool rng;
if (!pubKey.Validate(rng, 3))
    throw std::exception("Rsa private key validation failed");

////////////////////////////////////////////////
// Encryption
RSAES_PKCS1v15_Encryptor enc(pubKey);
StringSource ss1(data, true,
        new PK_EncryptorFilter(rng, enc,
            new StringSink(retStr)
        ));

std::string retData2 = "";

StringSource ss2((const byte*)retStr.data(), retStr.size(), true,
        new Base64Encoder(
            new StringSink(retData2)
        ));

retStr = retData2;

还有我的 javascript 代码

// nStr in CPP is "0x" + localStorage.getItem("rsa_public")  from javascript
// data in CPP is "secret"

var rsa = new RSAKey();
var publickey = localStorage.getItem("rsa_public");
var privatekey = localStorage.getItem("rsa_private");
rsa.setPrivate(publickey, "10001", privatekey);
alert(b64tohex(dec) + "\n" + rsa.encrypt("secret")); <-- these don't match at all .. and ofc rsa.decrypt returns null

dec in javascript 是来自 CPP

的 retStr

JSBN 和您的 Crypto++ 代码使用的 PKCS#1 v1.5 填充是随机填充,因此如果您使用相同的密钥加密数据,它看起来会有所不同。您必须通过在一端加密和在另一端双向解密来检查您的实现是否有效。

RSAES_PKCS1v15_Encryptor enc(pubKey);
StringSource ss1(data, true,
        new PK_EncryptorFilter(rng, enc,
            new StringSink(retStr)
        ));
...
StringSource ss2((const byte*)retStr.data(), retStr.size(), true,
        new Base64Encoder(
            new StringSink(retData2)
        ));

我不确定这是否正确与 Javascript 和 JSBN 的互操作。单独使用是正确的,与 OpenSSL 互操作也是正确的。

Crypto++ 使用早期的 Base64 编码方案。它出现在当时的电子邮件和其他标准中(时间大约是 1990 年代)。字母表使用加号 (+) 和正斜杠 (/) 字符。

Javascript 和 JSON 技术,如 JSON Web Keys (JWKs) 倾向于支持使用 URL 或 Web Safe 字母表的 Base64 编码。字母表使用减号 (-) 和下划线 (_) 字符。

RFC 4648, The Base16, Base32, and Base64 Data Encodings中指定了新旧Base64编码方案。

您应该获取 Base64URLEncoder 的补丁,并在 Crypto++ 源代码之上就地应用它。修补后,您将拥有现有的 Base6Encoder 和新的 Base64URLEncoder。最后,重新编译并重新安装库。你必须修补它,因为它不是 Wei Dai 编写和提供的 Crypto++ 库的一部分。

然后,执行以下操作:

RSAES_PKCS1v15_Encryptor enc(pubKey);
string encoded;

StringSource ss(data, true,
        new PK_EncryptorFilter(prng, enc,
            new Base64URLEncoder(
                new StringSink(encoded)
        )));

// Print encoded cipher text
cout << encoded << endl;

return encoded;

至于 “这些根本不匹配...” - 我认为这是预料之中的。 RSA 加密使用随机填充,因此当您加密消息 m1m2 时,密文是不同的。它被称为“语义安全”,是一个强大(更强?)的安全概念。这样,坏人就无法判断同一条消息何时被发送了两次。