在 RSA 下解码有效负载后未获得相同的会话密钥
Not getting same session key after decoding payload under RSA
使用以下使用 crypto++ 库的函数对其进行编码和解码后,我没有得到相同的会话密钥:
CryptoPP::RSA::PrivateKey RSA_master_privKey;
CryptoPP::RSA::PublicKey RSA_master_pubKey;
std::string generate_Master_Keys()
{
std::string rsaParams;
try {
CryptoPP::InvertibleRSAFunction parameters;
RSA_master_privKey = CryptoPP::RSA::PrivateKey(parameters);
RSA_master_pubKey = CryptoPP::RSA::PublicKey(parameters);
}
catch (const CryptoPP::Exception& e)
{
std::cerr << e.what() << std::endl;
b_success = false;
}
return rsaParams;
}
PAES_KEY_WITH_IV create_session_key(void)
{
CryptoPP::AutoSeededX917RNG<CryptoPP::AES> rng;
PAES_KEY_WITH_IV aes_info = new AES_KEY_WITH_IV;
try {
aes_info->key.resize(CryptoPP::AES::DEFAULT_KEYLENGTH);
rng.GenerateBlock(aes_info->key, aes_info->key.size());
aes_info->iv.resize(CryptoPP::AES::BLOCKSIZE);
rng.GenerateBlock(&aes_info->iv[0], aes_info->iv.size());
}
catch (const CryptoPP::Exception& e)
{
std::cerr << e.what() << std::endl;
b_success = false;
}
return (aes_info);
}
std::string encrypt_session_key(PAES_KEY_WITH_IV pKey)
{
std::string ciphered;
CryptoPP::SecByteBlock block(pKey->key.size());
try {
CryptoPP::RSAES< CryptoPP::OAEP<CryptoPP::SHA> >::Encryptor enc(RSA_master_pubKey);
enc.Encrypt(rng, pKey->key, pKey->key.size(), block);
ciphered.assign((char *)block.BytePtr(), 192);
}
catch (const CryptoPP::Exception& e)
{
std::cerr << e.what() << std::endl;
b_success = false;
}
return ciphered;
}
PAES_KEY_WITH_IV decrypt_session_key(std::string & ciphered)
{
CryptoPP::SecByteBlock rec(ciphered.size());
CryptoPP::SecByteBlock block((const byte *)ciphered.data(), ciphered.size());
PAES_KEY_WITH_IV pKey = new AES_KEY_WITH_IV;
try {
CryptoPP::RSAES< CryptoPP::OAEP<CryptoPP::SHA> >::Decryptor dec(RSA_master_privKey);
dec.Decrypt(rng, block, block.size(), rec);
pKey->key = rec;
}
catch (const CryptoPP::Exception& e)
{
std::cerr << e.what() << std::endl;
b_success = false;
}
return pKey;
}
192 字节的拖尾与原始会话密钥的字节不匹配。
有人可以帮我解决这个问题吗?
提前致谢。
I am not getting same session key after encoding and decoding it using below functions
我认为您已接近您的需要。还有机会改进您的工作方式。我会告诉你改进的方法,你也可以把它应用到现有的方法中。
改进后的方法就是简单的用FixedMaxPlaintextLength
、CiphertextLength
和一些朋友来确定尺寸。它还使用了 Integrated Encryption Schemes (IES).
中的技术
首先,传输原始种子字节,而不是 {key, iv}
对。然后,当您需要 {key, iv}
对时,您可以从种子字节中导出所需的字节。您的推导应包括使用标签和版本号。
其次,悬而未决的问题:您将多少字节作为种子字节传输。答案是 FixedMaxPlaintextLength()
或 MaxPreimage()
(我不记得是哪个)。这是该方案下可以加密的明文大小,它取决于模数大小和填充方案。
下面的许多代码在 RSA Encryption Schemes 和 Crypto++ wiki 的其他地方进行了讨论。但是,由于您仍在学习一些技术,因此您需要访问它们并不明显。
以下生成随机种子并在 public 密钥下对其进行加密。
RSA_master_pubKey = RSA::PublicKey(parameters);
RSAES< OAEP<SHA> >::Encryptor enc(RSA_master_pubKey);
SecByteBlock seed(enc.FixedMaxPlaintextLength());
AutoSeededX917RNG<AES> rng;
rng.GenerateBlock(seed, seed.size());
SecByteBlock block(enc.CiphertextLength(seed.size())));
size_t req = enc.Encrypt(rng, seed, seed.size(), block);
block.resize(req);
// Transport block to peer as session seed
当对等方收到加密的种子块时,他们必须对其进行解密。方法如下。
// Received from peer
SecByteBlock block(...);
RSAES< OAEP<SHA> >::Decryptor dec(RSA_master_privKey);
size_t req = dec.MaxPlaintextLength(block.size());
SecByteBlock seed(req);
DecodingResult result = dec.Decrypt(rng, block, block.size(), seed);
seed.resize(result.isValidCoding ? result.messageLength : 0);
如果 result.isValidCoding
returns false
:
你甚至可以抛出异常
DecodingResult result = dec.Decrypt(rng, block, block.size(), seed);
if (!result.isValidCoding)
throw Exception(OTHER_ERROR, "Failed to decrypt seed bytes");
seed.resize(result.messageLength);
当你想用 AES 加密或解密时,你需要派生一个密钥,iv 和可能的 hmac 密钥(你在验证数据吗?)。
// Random seed from above
SecByteBlock seed;
HKDF<SHA256> kdf;
SecByteBlock aesKey(AES::DEFAULT_KEYLENGTH);
SecByteBlock aesIV(AES::BLOCKSIZE);
const byte aesLabel[] = "AES encryption key, version 1";
kdf.Derive(aesKey, aesKey.size(), seed, seed.size(), NULL, 0, aesLabel, COUNTOF(aesLabel));
const byte ivLabel[] = "AES initialization vector, version 1";
kdf.Derive(aesIV, aesIV.size(), seed, seed.size(), NULL, 0, ivLabel, COUNTOF(ivLabel));
如果 您验证了您的数据,那么您可以使用以下内容导出 HMAC 密钥。但一般来说,您应该使用 Authenticated Encryption 操作模式:
const byte hmacLabel[] = "HMAC authentication key, version 1";
kdf.Derive(hmacKey, hmacKey.size(), seed, seed.size(), NULL, 0, hmacLabel, COUNTOF(hmacLabel));
HKDF was added at 5.6.3 or 5.6.4. If you don't have it, then grab hkdf.h
from Wei Dai's GitHub(其 header-only)。通过从具有唯一标签的基本种子派生,您正在使用一种称为独立派生的技术。
您添加标签和版本信息以避免 Attacking and Repairing the WinZip Encryption Scheme 中讨论的差距。此外,使用整个 FixedMaxPlaintextLength
侧步骤进行一些与消息长度相关的加密攻击。
您可能还想看看 Integrated Encryption Schemes (IES)。我们基本上从 IES 中取消了密钥封装机制 (KEM)。还有一个数据封装机制 (DEM) 也可以取消。
如果你打算借用KEM和DEM,那你不妨使用这个方案。为此,请参阅 Crypto++ wiki 上的以下内容:
如果您使用其中一种集成加密方案,那么您正在改变潜在的数学问题。 RSA 是 Integer Factorization (IF),而 IES 是 Diffie-Hellman 和 Discrete Logs ( FF).
使用集成加密方案是一个不错的选择。它是 IND-CCA2,这是一个非常强大的安全概念。我相信它比你原来的方案有更好的安全属性。
使用以下使用 crypto++ 库的函数对其进行编码和解码后,我没有得到相同的会话密钥:
CryptoPP::RSA::PrivateKey RSA_master_privKey;
CryptoPP::RSA::PublicKey RSA_master_pubKey;
std::string generate_Master_Keys()
{
std::string rsaParams;
try {
CryptoPP::InvertibleRSAFunction parameters;
RSA_master_privKey = CryptoPP::RSA::PrivateKey(parameters);
RSA_master_pubKey = CryptoPP::RSA::PublicKey(parameters);
}
catch (const CryptoPP::Exception& e)
{
std::cerr << e.what() << std::endl;
b_success = false;
}
return rsaParams;
}
PAES_KEY_WITH_IV create_session_key(void)
{
CryptoPP::AutoSeededX917RNG<CryptoPP::AES> rng;
PAES_KEY_WITH_IV aes_info = new AES_KEY_WITH_IV;
try {
aes_info->key.resize(CryptoPP::AES::DEFAULT_KEYLENGTH);
rng.GenerateBlock(aes_info->key, aes_info->key.size());
aes_info->iv.resize(CryptoPP::AES::BLOCKSIZE);
rng.GenerateBlock(&aes_info->iv[0], aes_info->iv.size());
}
catch (const CryptoPP::Exception& e)
{
std::cerr << e.what() << std::endl;
b_success = false;
}
return (aes_info);
}
std::string encrypt_session_key(PAES_KEY_WITH_IV pKey)
{
std::string ciphered;
CryptoPP::SecByteBlock block(pKey->key.size());
try {
CryptoPP::RSAES< CryptoPP::OAEP<CryptoPP::SHA> >::Encryptor enc(RSA_master_pubKey);
enc.Encrypt(rng, pKey->key, pKey->key.size(), block);
ciphered.assign((char *)block.BytePtr(), 192);
}
catch (const CryptoPP::Exception& e)
{
std::cerr << e.what() << std::endl;
b_success = false;
}
return ciphered;
}
PAES_KEY_WITH_IV decrypt_session_key(std::string & ciphered)
{
CryptoPP::SecByteBlock rec(ciphered.size());
CryptoPP::SecByteBlock block((const byte *)ciphered.data(), ciphered.size());
PAES_KEY_WITH_IV pKey = new AES_KEY_WITH_IV;
try {
CryptoPP::RSAES< CryptoPP::OAEP<CryptoPP::SHA> >::Decryptor dec(RSA_master_privKey);
dec.Decrypt(rng, block, block.size(), rec);
pKey->key = rec;
}
catch (const CryptoPP::Exception& e)
{
std::cerr << e.what() << std::endl;
b_success = false;
}
return pKey;
}
192 字节的拖尾与原始会话密钥的字节不匹配。
有人可以帮我解决这个问题吗?
提前致谢。
I am not getting same session key after encoding and decoding it using below functions
我认为您已接近您的需要。还有机会改进您的工作方式。我会告诉你改进的方法,你也可以把它应用到现有的方法中。
改进后的方法就是简单的用FixedMaxPlaintextLength
、CiphertextLength
和一些朋友来确定尺寸。它还使用了 Integrated Encryption Schemes (IES).
首先,传输原始种子字节,而不是 {key, iv}
对。然后,当您需要 {key, iv}
对时,您可以从种子字节中导出所需的字节。您的推导应包括使用标签和版本号。
其次,悬而未决的问题:您将多少字节作为种子字节传输。答案是 FixedMaxPlaintextLength()
或 MaxPreimage()
(我不记得是哪个)。这是该方案下可以加密的明文大小,它取决于模数大小和填充方案。
下面的许多代码在 RSA Encryption Schemes 和 Crypto++ wiki 的其他地方进行了讨论。但是,由于您仍在学习一些技术,因此您需要访问它们并不明显。
以下生成随机种子并在 public 密钥下对其进行加密。
RSA_master_pubKey = RSA::PublicKey(parameters);
RSAES< OAEP<SHA> >::Encryptor enc(RSA_master_pubKey);
SecByteBlock seed(enc.FixedMaxPlaintextLength());
AutoSeededX917RNG<AES> rng;
rng.GenerateBlock(seed, seed.size());
SecByteBlock block(enc.CiphertextLength(seed.size())));
size_t req = enc.Encrypt(rng, seed, seed.size(), block);
block.resize(req);
// Transport block to peer as session seed
当对等方收到加密的种子块时,他们必须对其进行解密。方法如下。
// Received from peer
SecByteBlock block(...);
RSAES< OAEP<SHA> >::Decryptor dec(RSA_master_privKey);
size_t req = dec.MaxPlaintextLength(block.size());
SecByteBlock seed(req);
DecodingResult result = dec.Decrypt(rng, block, block.size(), seed);
seed.resize(result.isValidCoding ? result.messageLength : 0);
如果 result.isValidCoding
returns false
:
DecodingResult result = dec.Decrypt(rng, block, block.size(), seed);
if (!result.isValidCoding)
throw Exception(OTHER_ERROR, "Failed to decrypt seed bytes");
seed.resize(result.messageLength);
当你想用 AES 加密或解密时,你需要派生一个密钥,iv 和可能的 hmac 密钥(你在验证数据吗?)。
// Random seed from above
SecByteBlock seed;
HKDF<SHA256> kdf;
SecByteBlock aesKey(AES::DEFAULT_KEYLENGTH);
SecByteBlock aesIV(AES::BLOCKSIZE);
const byte aesLabel[] = "AES encryption key, version 1";
kdf.Derive(aesKey, aesKey.size(), seed, seed.size(), NULL, 0, aesLabel, COUNTOF(aesLabel));
const byte ivLabel[] = "AES initialization vector, version 1";
kdf.Derive(aesIV, aesIV.size(), seed, seed.size(), NULL, 0, ivLabel, COUNTOF(ivLabel));
如果 您验证了您的数据,那么您可以使用以下内容导出 HMAC 密钥。但一般来说,您应该使用 Authenticated Encryption 操作模式:
const byte hmacLabel[] = "HMAC authentication key, version 1";
kdf.Derive(hmacKey, hmacKey.size(), seed, seed.size(), NULL, 0, hmacLabel, COUNTOF(hmacLabel));
HKDF was added at 5.6.3 or 5.6.4. If you don't have it, then grab hkdf.h
from Wei Dai's GitHub(其 header-only)。通过从具有唯一标签的基本种子派生,您正在使用一种称为独立派生的技术。
您添加标签和版本信息以避免 Attacking and Repairing the WinZip Encryption Scheme 中讨论的差距。此外,使用整个 FixedMaxPlaintextLength
侧步骤进行一些与消息长度相关的加密攻击。
您可能还想看看 Integrated Encryption Schemes (IES)。我们基本上从 IES 中取消了密钥封装机制 (KEM)。还有一个数据封装机制 (DEM) 也可以取消。
如果你打算借用KEM和DEM,那你不妨使用这个方案。为此,请参阅 Crypto++ wiki 上的以下内容:
如果您使用其中一种集成加密方案,那么您正在改变潜在的数学问题。 RSA 是 Integer Factorization (IF),而 IES 是 Diffie-Hellman 和 Discrete Logs ( FF).
使用集成加密方案是一个不错的选择。它是 IND-CCA2,这是一个非常强大的安全概念。我相信它比你原来的方案有更好的安全属性。