【问题标题】:Crypto++ and Compressed EC keysCrypto++ 和压缩 EC 密钥
【发布时间】:2013-05-15 23:06:25
【问题描述】:

如何在 Crypto++ 中生成压缩的 ECDSA 密钥?

AutoSeededRandomPool prng;
ECDSA<ECP, SHA1>::PrivateKey privateKey;
ECDSA<ECP, SHA1>::PublicKey publicKey;
privateKey.Initialize( prng, CryptoPP::ASN1::secp256r1());

const Integer& x1 = privateKey.GetPrivateExponent();
cout << "priv:  " << std::hex << x1 << endl;
privateKey.MakePublicKey( publicKey );
const ECP::Point& q = publicKey.GetPublicElement();
const Integer& qx = q.x;
const Integer& qy = q.y;
cout << "pub x: " << std::hex << qx << endl;
cout << "pub y: " << std::hex << qy << endl;

此代码生成一个密钥对并打印公钥的 X 和 Y 分量。

我需要知道是否有办法打印压缩密钥的 Y 分量,或者我是否需要从未压缩的 y 分量生成它。如果我需要生成它,有人可以将我链接到如何使用 Integer 类的一个很好的解释吗?

【问题讨论】:

    标签: c++ crypto++


    【解决方案1】:

    如何在 CryptoPP 中生成压缩的 ECDSA 密钥?

    您不创建压缩密钥。您生成一个公钥,然后在需要时对其进行压缩。来自 Crpyto++ 用户组的How to construct a public ECDSA key with point compression turned on?

    ECDSA<ECP, SHA1>::Verifier verifier(...);
    verifier.AccessKey().AccessGroupParameters().SetPointCompression(true); 
    

    在你的情况下,它将是:

    publicKey.AccessGroupParameters().SetPointCompression(true);
    

    因为 verifier.AccessKey() 返回 ECDSA 公钥。


    我需要知道是否有办法打印压缩键的 Y 分量

    压缩是一种演示格式选项或优化。您无法在带有压缩的序列化密钥上打印 Y 组件,因为它不存在(请参阅下面的 ASN.1 转储)。

    启用压缩后,Y“速记”将是 1 或 -1,具体取决于组件的符号(符号表示该点所在的象限)。这个想法是有人给你发送一个 {1,X} 对或 {-1,X} 对,你可以求解 Y,因为你知道它应该在哪个象限。如果只允许 Y 为正,你只需要序列化 {X}(而不是 {-1,X} 或 {1,X})。 (我没有深入研究书籍或标准,所以这里可能有一些勘误)。


    ... 或者如果我需要从未压缩的 y 分量生成它。如果我需要生成它,有人可以将我链接到如何使用 Integer 类的一个很好的解释吗?

    我不知道你在这里说什么。点压缩会影响呈现。如果你打开点压缩并获取 Y,你仍然会得到 Y。您无法在压缩点上进行计算。您需要 X 和 Y 坐标。


    将以下内容添加到您的程序中:

    publicKey.AccessGroupParameters().SetPointCompression(false);
    ByteQueue q1;
    publicKey.Save(q1);
    cout << "Uncompressed size: " << dec << q1.MaxRetrievable() << endl;
    
    publicKey.AccessGroupParameters().SetPointCompression(true);
    ByteQueue q2;
    publicKey.Save(q2);
    cout << "Compressed size: " << dec << q2.MaxRetrievable() << endl;
    

    这是我得到的输出:

    $ ./cryptopp-test.exe
    priv:  4ce30d22d9593d9c7f4406eda1ce0740c7486106374d0abe7e352e1d5b1d5622h
    pub x: 41a9bc936b6d1dd3a1ded997d7da08f1df990e9b50f9b58e9e4fd9319758ea34h
    pub y: 4ad39ffb79c402063a99ecbc0cac8fde606db6764ace90933feee5f8d65937a2h
    Uncompressed size: 311
    Compressed size: 246
    

    如果你在开启点压缩后获取 Y,你仍然会得到 4ad39ffb79c402063a99ecbc0cac8fde606db6764ace90933feee5f8d65937a2h,因为压缩会影响显示。


    现在,添加以下内容以转储未压缩和压缩的密钥:

    FileSink fs1("key-1.der", true);
    q1.TransferTo(fs1);
    
    FileSink fs2("key-2.der", true);
    q2.TransferTo(fs2);
    

    密钥以 ASN.1 的 DER 编码转储,并符合 Certicom 的 SEC 1: Elliptic Curve Cryptography(在较小程度上,ANSI 9.62RFC 5480, ECC SubjectPublicKeyInfo Format - 请参阅下面的字段元素 OCTET STRINGBIT STRING)。

    您可以在他们身上运行 Peter Gutmann 的 dumpasn1

    $ dumpasn1.exe key-1.der 
      0 307: SEQUENCE {
      4 236:   SEQUENCE {
      7   7:     OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
     16 224:     SEQUENCE {
     19   1:       INTEGER 1
     22  44:       SEQUENCE {
     24   7:         OBJECT IDENTIFIER prime-field (1 2 840 10045 1 1)
     33  33:         INTEGER
           :           00 FF FF FF FF 00 00 00 01 00 00 00 00 00 00 00
           :           00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF
           :           FF
           :         }
     68  68:       SEQUENCE {
     70  32:         OCTET STRING
           :           FF FF FF FF 00 00 00 01 00 00 00 00 00 00 00 00
           :           00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FC
    104  32:         OCTET STRING
           :           5A C6 35 D8 AA 3A 93 E7 B3 EB BD 55 76 98 86 BC
           :           65 1D 06 B0 CC 53 B0 F6 3B CE 3C 3E 27 D2 60 4B
           :         }
    138  65:       OCTET STRING
           :         04 6B 17 D1 F2 E1 2C 42 47 F8 BC E6 E5 63 A4 40
           :         F2 77 03 7D 81 2D EB 33 A0 F4 A1 39 45 D8 98 C2
           :         96 4F E3 42 E2 FE 1A 7F 9B 8E E7 EB 4A 7C 0F 9E
           :         16 2B CE 33 57 6B 31 5E CE CB B6 40 68 37 BF 51
           :         F5
    205  33:       INTEGER
           :         00 FF FF FF FF 00 00 00 00 FF FF FF FF FF FF FF
           :         FF BC E6 FA AD A7 17 9E 84 F3 B9 CA C2 FC 63 25
           :         51
    240   1:       INTEGER 1
           :       }
           :     }
    243  66:   BIT STRING
           :     04 41 A9 BC 93 6B 6D 1D D3 A1 DE D9 97 D7 DA 08
           :     F1 DF 99 0E 9B 50 F9 B5 8E 9E 4F D9 31 97 58 EA
           :     34 4A D3 9F FB 79 C4 02 06 3A 99 EC BC 0C AC 8F
           :     DE 60 6D B6 76 4A CE 90 93 3F EE E5 F8 D6 59 37
           :     A2
           :   }
    
    $ dumpasn1.exe key-2.der 
      0 243: SEQUENCE {
      3 204:   SEQUENCE {
      6   7:     OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
     15 192:     SEQUENCE {
     18   1:       INTEGER 1
     21  44:       SEQUENCE {
     23   7:         OBJECT IDENTIFIER prime-field (1 2 840 10045 1 1)
     32  33:         INTEGER
           :           00 FF FF FF FF 00 00 00 01 00 00 00 00 00 00 00
           :           00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF
           :           FF
           :         }
     67  68:       SEQUENCE {
     69  32:         OCTET STRING
           :           FF FF FF FF 00 00 00 01 00 00 00 00 00 00 00 00
           :           00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FC
    103  32:         OCTET STRING
           :           5A C6 35 D8 AA 3A 93 E7 B3 EB BD 55 76 98 86 BC
           :           65 1D 06 B0 CC 53 B0 F6 3B CE 3C 3E 27 D2 60 4B
           :         }
    137  33:       OCTET STRING
           :         03 6B 17 D1 F2 E1 2C 42 47 F8 BC E6 E5 63 A4 40
           :         F2 77 03 7D 81 2D EB 33 A0 F4 A1 39 45 D8 98 C2
           :         96
    172  33:       INTEGER
           :         00 FF FF FF FF 00 00 00 00 FF FF FF FF FF FF FF
           :         FF BC E6 FA AD A7 17 9E 84 F3 B9 CA C2 FC 63 25
           :         51
    207   1:       INTEGER 1
           :       }
           :     }
    210  34:   BIT STRING
           :     02 41 A9 BC 93 6B 6D 1D D3 A1 DE D9 97 D7 DA 08
           :     F1 DF 99 0E 9B 50 F9 B5 8E 9E 4F D9 31 97 58 EA
           :     34
           :   }
    

    注意区别:

    # key-1.der
    243  66:   BIT STRING
           :     04 41 A9 BC 93 6B 6D 1D D3 A1 DE D9 97 D7 DA 08
           :     F1 DF 99 0E 9B 50 F9 B5 8E 9E 4F D9 31 97 58 EA
           :     34 4A D3 9F FB 79 C4 02 06 3A 99 EC BC 0C AC 8F
           :     DE 60 6D B6 76 4A CE 90 93 3F EE E5 F8 D6 59 37
           :     A2
    

    对比:

    # key-2.der
    210  34:   BIT STRING
           :     02 41 A9 BC 93 6B 6D 1D D3 A1 DE D9 97 D7 DA 08
           :     F1 DF 99 0E 9B 50 F9 B5 8E 9E 4F D9 31 97 58 EA
           :     34
           :   }
    

    第一个有两个 Integer 编码,而第二个有一个 Integer 编码。通用值为41 A9 BC 93 ... 97 58 EA 34,即上面的pub x。 key-2 中缺少的字符串是4A D3 9F FB ... D6 59 37 A2,也就是上面的pub y。为了完整起见,这些值被编码为 {X,Y} 或 {X},而不是 ASN.1 的整数编码。

    最后的区别是 BIT STRING 的 第一个八位字节:02 与 04(或 03)。 04 表示它是一个未压缩的点。来自 RFC 5480,第 2.2 节:

        The first octet of the OCTET STRING indicates whether the key is
        compressed or uncompressed.  The uncompressed form is indicated
        by 0x04 and the compressed form is indicated by either 0x02 or
        0x03 (see 2.3.3 in [SEC1]).  The public key MUST be rejected if
        any other value is included in the first octet.
    

    在查看标准和第 2.2 节之后,Crypto++ 可能有一个错误:它写了一个BIT STRING,但标准显然在讨论一个OCTET STRING

    编辑 1:这似乎也是 ANSI 9.62 下的 Crypto++ 错误。第 6.2 节,有限域元素和椭圆曲线点的语法(第 20 页)

        A finite field element shall be represented by a value of type FieldElement:
          FieldElement ::= OCTET STRING
        The value of FieldElement shall be the octet string representation of a field
        elementfollowing the conversion routine in Section 4.3.1.
        An elliptic curve point shall be represented by a value of type ECPoint:
          ECPoint ::= OCTET STRING
    

    编辑 2:Crypto++ 使用 Certicom 的 SEC 1: Elliptic Curve Cryptography 指定的格式。附录 C(第 77 页)指出:

        Finally, a specific field element is represented by the following type
          FieldElement ::= OCTET STRING
        whose value is the octet string obtained from the conversion routines
        given in Section 2.3.5.
    

    【讨论】: