【问题标题】:BER decode errorBER解码错误
【发布时间】:2018-05-21 05:40:22
【问题描述】:

我正在做 RSA 签名验证,我总是会得到这个错误

terminate called after throwing an instance of 'CryptoPP::BERDecodeErr'
  what():  BER decode error
Aborted (core dumped)

我不明白为什么会出现此错误,我之前从未调用过 BERDecode。

这是我的代码段,我试图追踪它在第二行代码中发生的错误:

FileSource pubFile(publicKey_file.c_str(), true, new HexDecoder);
RSASS<PSSR, SHA1>::Verifier pub(pubFile);

FileSource signatureFile(sig_file.c_str(), true, new HexDecoder);   
if (signatureFile.MaxRetrievable() != pub.SignatureLength()) {
    return false;
}

SecByteBlock signature(pub.SignatureLength());
signatureFile.Get(signature, signature.size());

bool result = pub.VerifyMessage((const byte*)messages_file.c_str(),
messages_file.length(), signature, signature.size());

return result;

我可以定义出了什么问题,希望能得到一些帮助。谢谢。

【问题讨论】:

  • 欢迎来到 StackOverflow Lilian。请注意,您正在尝试执行签名以提供 消息恢复 (PSSR),这是故意的吗?通常使用 SSA 方案。
  • 请提供您的公钥。使用类似hexdump -C &lt;public_key&gt; 的命令。通过单击编辑将其添加到问题中。另请参阅 Crypto++ wiki 上的 Keys and Formats

标签: c++ cryptography rsa crypto++


【解决方案1】:

您正在尝试加载一个公钥,需要先对其进行解析,然后才能进行任何验证。为此,您将公钥数据提供给Verifier 构造函数。此构造函数尝试解析公钥。

现在公钥通常是编码的数据结构。这些数据结构由称为 ASN.1 或抽象语法表示法 1 的数据描述语言描述,并使用称为 BER 的方案(ASN.1 的基本编码规则)进行编码。

所以发生的情况是构造函数尝试读取公钥并因此调用BERDecode,所以要理解输入。不幸的是,输入可能根本不是二进制 BER 编码的。

因此,要解决此问题,您需要在应用程序中使用额外的调用来转换为 BER 或公钥对象,或者您需要将您的密钥转换为 BER。如果密钥是 ASCII 铠装(PEM 格式),那么您可以使用:

$ openssl rsa -pubin -inform PEM -in <filename of key in PEM format> -outform DER -out <filename of key in DER format>

如果这不起作用,请将公钥包含在您的问题中,以便我们检查它为什么无法解析。

【讨论】:

  • 我试过那个方法但是还是不行。这是我的公共密钥: 30819D300D06092A864886F70D010101050003818B0030818702818100DD2CED773D6F9AE4A63F2DAEEF9019C056D4A35F338764FAAE85EDCBFB13FC9E53F13CEFADEF58C65B501C3D2D13DCDE65282B7781C45259065F991C4184E6E6DEDB3087472B4AC4BDD74FDF4D3C893257D6872232651653A4882588C61C0F4FB096C5906F2F88E0480513A2B1BA6418869DB01C9D9A2FB4BECADE54658D552F020111 B> SPAN>
  • 这是一个 X.509v3 SubjectPublicKey。你能看看here?我有一些购物要做。
【解决方案2】:

根据:

$ echo "30819D300D06092A864886F70D010101050003818B0030818702818100DD2CED773D6F9A
E4A63F2DAEEF9019C056D4A35F338764FAAE85EDCBFB13FC9E53F13CEFADEF58C65B501C3D2D13DC
DE65282B7781C45259065F991C4184E6E6DEDB3087472B4AC4BDD74FDF4D3C893257D68722326516
53A4882588C61C0F4FB096C5906F2F88E0480513A2B1BA6418869DB01C9D9A2FB4BECADE54658D55
2F020111" | xxd -r -p > key.ber

然后:

$ dumpasn1 key.ber
  0 157: SEQUENCE {
  3  13:   SEQUENCE {
  5   9:     OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
 16   0:     NULL
       :     }
 18 139:   BIT STRING, encapsulates {
 22 135:     SEQUENCE {
 25 129:       INTEGER
       :         00 DD 2C ED 77 3D 6F 9A E4 A6 3F 2D AE EF 90 19
       :         C0 56 D4 A3 5F 33 87 64 FA AE 85 ED CB FB 13 FC
       :         9E 53 F1 3C EF AD EF 58 C6 5B 50 1C 3D 2D 13 DC
       :         DE 65 28 2B 77 81 C4 52 59 06 5F 99 1C 41 84 E6
       :         E6 DE DB 30 87 47 2B 4A C4 BD D7 4F DF 4D 3C 89
       :         32 57 D6 87 22 32 65 16 53 A4 88 25 88 C6 1C 0F
       :         4F B0 96 C5 90 6F 2F 88 E0 48 05 13 A2 B1 BA 64
       :         18 86 9D B0 1C 9D 9A 2F B4 BE CA DE 54 65 8D 55
       :         2F
157   1:       INTEGER 17
       :       }
       :     }
       :   }

您有一个subjectPublicKeyInfo。我相信你需要做的就是打电话给Load,但它假设你有一个格式正确的密钥:

RSASS<PSSR, SHA1>::Verifier pub;
pub.AccessKey().Load(pubFile);

这是整个程序:

$ cat test.cxx
#include "cryptlib.h"
#include "filters.h"
#include "pssr.h"
#include "sha.h"
#include "rsa.h"
#include "hex.h"

#include <string>
#include <iostream>

int main()
{
    using namespace CryptoPP;
    std::string encodedKey = "30819D300D06092A864886F70D010101050003818B00"
        "30818702818100DD2CED773D6F9AE4A63F2DAEEF9019C056D4A35F338764FAAE8"
        "5EDCBFB13FC9E53F13CEFADEF58C65B501C3D2D13DCDE65282B7781C45259065F"
        "991C4184E6E6DEDB3087472B4AC4BDD74FDF4D3C893257D6872232651653A4882"
        "588C61C0F4FB096C5906F2F88E0480513A2B1BA6418869DB01C9D9A2FB4BECADE"
        "54658D552F020111";

    StringSource hexKey(encodedKey, true, new HexDecoder);

    RSASS<PSSR, SHA1>::Verifier pub;
    pub.AccessKey().Load(hexKey);

    std::cout << "n: " << std::hex << pub.AccessKey().GetModulus() << std::endl;
    std::cout << "e: " << std::dec << pub.AccessKey().GetPublicExponent() << std::endl;

    return 0;
}

最后:

$ ./test.exe
n: dd2ced773d6f9ae4a63f2daeef9019c056d4a35f338764faae85edcbfb13fc9e53f13cefadef5
8c65b501c3d2d13dcde65282b7781c45259065f991c4184e6e6dedb3087472b4ac4bdd74fdf4d3c8
93257d6872232651653a4882588c61c0f4fb096c5906f2f88e0480513a2b1ba6418869db01c9d9a2
fb4becade54658d552fh
e: 17.

这可能有点太严格了:

if (signatureFile.MaxRetrievable() != pub.SignatureLength()) {
    return false;
}

实际签名长度可能比MaxSignatureLength() 短一点,具体取决于求幂产生的前导 0 的数量。

您可以考虑遵循 wiki 示例之一。比如来自RSA Signature Schemes

...

// Signing      
RSASS<PSSR, SHA1>::Signer signer(privateKey);
RSASS<PSSR, SHA1>::Verifier verifier(publicKey);

// Setup
byte message[] = "RSA-PSSR Test";
size_t messageLen = sizeof(message);      

////////////////////////////////////////////////
// Sign and Encode
SecByteBlock signature(signer.MaxSignatureLength(messageLen));

size_t signatureLen = signer.SignMessageWithRecovery(rng, message, messageLen, NULL, 0, signature);

// Resize now we know the true size of the signature
signature.resize(signatureLen);

////////////////////////////////////////////////
// Verify and Recover
SecByteBlock recovered(
    verifier.MaxRecoverableLengthFromSignatureLength(signatureLen)
);

DecodingResult result = verifier.RecoverMessage(recovered, NULL, 0, signature, signatureLen);

if (!result.isValidCoding) {
    throw Exception(Exception::OTHER_ERROR, "Invalid Signature");
}

////////////////////////////////////////////////
// Use recovered message
//  MaxSignatureLength is likely larger than messageLength
recovered.resize(result.messageLength);
...

【讨论】:

  • 我认为致电Load() 可以很好地解决问题。请注意,关于任何 RSA 应用程序都使用称为 I2OSP 的函数,它将签名作为数字的大小转换为与密钥大小(或模数大小)相同大小的八位字节字符串(以字节为单位)。所以我不同意答案的那一部分。 +1 当然可以解决原始问题。
  • 或者您是否有任何迹象表明可恢复签名不会对签名执行此最终操作?
  • @Maarten - 我相信MaxSignatureLengthn-1。我认为 OP 正在测试签名中的八位字节数(signatureFile.MaxRetrievable())与模数中的八位字节数(pub.SignatureLength())相同。我认为这有点偏离目标。我相信持有的条件或关系是signatureFile.MaxRetrievable() &lt;= pub.SignatureLength()
  • 查看第一段here
  • 谢谢@Maarteen。我正在查看pssr.cpp 的源代码,但我无法真正说出一些期望是什么。如果问题不正确,您的观察结果是可用的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-10
  • 1970-01-01
  • 2019-12-10
  • 1970-01-01
相关资源
最近更新 更多