当前位置: 首页 > 知识库问答 >
问题:

使用 SHA-384 签署 ECDSA 时,“标量不在区间 [1, n - 1] 中”异常

荆煌
2023-03-14

我想使用SHA-384生成384位椭圆曲线签名,以生成我运行以下步骤的密钥,方法是查看此SO从OpenSSL命令行生成EC密钥对

openssl ecparam -name secp384r1 -genkey -noout -out d:/private.ec.key
openssl ec -in d:/private.pem -pubout -out d:/public.pem
openssl pkcs8 -topk8 -nocrypt -in d:/private.ec.key -out d:/private.pem

当我被要求输入密码时,我按了enter键(因为我不想有密码保护的密钥)。

然后我为我的JRE 14下载了BC prov-JDK 15 on-168 . jar Bouncy Castle lib,并将其添加到我的类路径中。并制作了小的测试应用程序,把这些密钥的内容直接复制到java源代码中去。

制作了一个简单的剥离方法来删除密钥的“文本”部分并解码其base 64内容:

  private static byte[] bytesFromKeyStrings(String string) {
    string = string.replaceAll("-----BEGIN PRIVATE KEY-----", "");
    string = string.replaceAll("-----BEGIN EC PRIVATE KEY-----", "");   
    string = string.replaceAll("-----END EC PRIVATE KEY-----", "");
    string = string.replaceAll("-----END PRIVATE KEY-----", "");    
    string = string.replaceAll("\r", "");
    string = string.replaceAll("\n", "");
    var bytes = Base64.getDecoder().decode(string);
    return bytes;
  }  

然后我从这些字节中产生一个私钥:

  private static PrivateKey keyFromBytes(byte[] pkcs8key) throws NoSuchAlgorithmException, InvalidKeySpecException {
    Security.addProvider(BOUNCY_CASTLE_PROVIDER);
    var spec = ECNamedCurveTable.getParameterSpec("secp384r1");;
    var ecPrivateKeySpec = new ECPrivateKeySpec(new BigInteger(1, pkcs8key), spec);
      
    var factory = KeyFactory.getInstance("ECDSA", BOUNCY_CASTLE_PROVIDER);
    return factory.generatePrivate(ecPrivateKeySpec);
  }

但是当我要使用PriateKey对消息进行签名(在本例中为零数组)时,我会得到异常:

  var key = keyFromBytes(bytesFromKeyStrings(privatePem));
  var ecdsaSign = Signature.getInstance("SHA384withECDSA", BOUNCY_CASTLE_PROVIDER);
  ecdsaSign.initSign(key, new SecureRandom());
  ecdsaSign.update(content);
  var signature = ecdsaSign.sign();

在线上造成:

ecdsaSign。initSign(key,new SecureRandom());

java.lang.IllegalArgumentException: Scalar is not in the interval [1, n - 1]
    at org.bouncycastle.provider/org.bouncycastle.crypto.params.ECDomainParameters.validatePrivateScalar(ECDomainParameters.java:146)
    at org.bouncycastle.provider/org.bouncycastle.crypto.params.ECPrivateKeyParameters.<init>(ECPrivateKeyParameters.java:16)
    at org.bouncycastle.provider/org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil.generatePrivateKeyParameter(ECUtil.java:245)
    at org.bouncycastle.provider/org.bouncycastle.jcajce.provider.asymmetric.ec.SignatureSpi.engineInitSign(Unknown Source)
    at java.base/java.security.SignatureSpi.engineInitSign(SignatureSpi.java:131)
    at java.base/java.security.Signature$Delegate.engineInitSign(Signature.java:1364)
    at java.base/java.security.Signature.initSign(Signature.java:658)
    at ecdsa/ecdsa.Main.main(Main.java:75)

如果我正确地理解ECDSA,我们需要将私钥乘以一些随机值,所以我为它提供了安全的Random。奇怪的是,我以前的尝试,当我没有尝试读取密钥并使用KeyPairGenerator.getInstance(“EC”)(没有弹跳城堡库)动态生成它们时,这些生成的密钥可用于无一例外地对消息进行签名,并且我单独验证了生成的签名是正确的。

我生产的密钥不好,还是有其他方法来提供乘数常量,所以它不试图直接与私钥签名并给我例外?

还是我错过了什么愚蠢的事情?

下面是我的测试应用程序的完整列表,它可以复制异常:

package ecdsa;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;

import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;

public class Main {
   
  private final static String privatePem = "-----BEGIN PRIVATE KEY-----\r\n"
      + "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBBdsy5smSA2+DvnIdx\r\n"
      + "bqq6GwwHadEdtHqcKO9N8hB0/NKvFOCmHBSfBpYPgCWlybGhZANiAAQ0iyw2wPjs\r\n"
      + "zhale0mPkiCCTzcNzTW1g7zqUoN3XNuZbaK1FHhVVMsywUaS6MSUJI6r1QcUziMm\r\n"
      + "MWGYZUSSq4noniTDt8INj/ElndKhbh3oSCq3j1oKK9cYXi3uGuDFXks=\r\n"
      + "-----END PRIVATE KEY-----\r\n";  
  
  private final static String privateEc = "-----BEGIN EC PRIVATE KEY-----\r\n"
      + "MIGkAgEBBDBBdsy5smSA2+DvnIdxbqq6GwwHadEdtHqcKO9N8hB0/NKvFOCmHBSf\r\n"
      + "BpYPgCWlybGgBwYFK4EEACKhZANiAAQ0iyw2wPjszhale0mPkiCCTzcNzTW1g7zq\r\n"
      + "UoN3XNuZbaK1FHhVVMsywUaS6MSUJI6r1QcUziMmMWGYZUSSq4noniTDt8INj/El\r\n"
      + "ndKhbh3oSCq3j1oKK9cYXi3uGuDFXks=\r\n"
      + "-----END EC PRIVATE KEY-----\r\n";
  
  private static final BouncyCastleProvider BOUNCY_CASTLE_PROVIDER = new BouncyCastleProvider();
  
  private static byte[] bytesFromKeyStrings(String string) {
    string = string.replaceAll("-----BEGIN PRIVATE KEY-----", "");
    string = string.replaceAll("-----BEGIN EC PRIVATE KEY-----", "");   
    string = string.replaceAll("-----END EC PRIVATE KEY-----", "");
    string = string.replaceAll("-----END PRIVATE KEY-----", "");    
    string = string.replaceAll("\r", "");
    string = string.replaceAll("\n", "");
    var bytes = Base64.getDecoder().decode(string);
    return bytes;
  }  
  
  
  private static PrivateKey keyFromBytes(byte[] pkcs8key) throws NoSuchAlgorithmException, InvalidKeySpecException {
    Security.addProvider(BOUNCY_CASTLE_PROVIDER);
    var spec = ECNamedCurveTable.getParameterSpec("secp384r1");;
    var ecPrivateKeySpec = new ECPrivateKeySpec(new BigInteger(1, pkcs8key), spec);
      
    var factory = KeyFactory.getInstance("ECDSA", BOUNCY_CASTLE_PROVIDER);
    return factory.generatePrivate(ecPrivateKeySpec);
  }
  
  
  public static void main(String[] args) {
    var content = new byte[100];
    
    try {
      var key = keyFromBytes(bytesFromKeyStrings(privatePem));
      var ecdsaSign = Signature.getInstance("SHA384withECDSA", BOUNCY_CASTLE_PROVIDER);
      ecdsaSign.initSign(key, new SecureRandom());
      ecdsaSign.update(content);
      
      var signature = ecdsaSign.sign();
    } catch (Exception e) {
      e.printStackTrace();
    }     
  }

}

编辑:更新了示例(之前我使用加密的私钥)

共有3个答案

屠德宇
2023-03-14

根据 https://lapo.it/asn1js/ 您在PEM编码中的私钥仍然是加密的 - 直接可见“-----开始加密的私钥-----”:

SEQUENCE (2 elem)
  SEQUENCE (2 elem)
    OBJECT IDENTIFIER 1.2.840.113549.1.5.13 pkcs5PBES2 (PKCS #5 v2.0)
    SEQUENCE (2 elem)
      SEQUENCE (2 elem)
        OBJECT IDENTIFIER 1.2.840.113549.1.5.12 pkcs5PBKDF2 (PKCS #5 v2.0)
        SEQUENCE (3 elem)
          OCTET STRING (8 byte) 1B9485597126CBC4
          INTEGER 2048
          SEQUENCE (2 elem)
            OBJECT IDENTIFIER 1.2.840.113549.2.9 hmacWithSHA256 (RSADSI digestAlgorithm)
            NULL
      SEQUENCE (2 elem)
        OBJECT IDENTIFIER 2.16.840.1.101.3.4.1.42 aes256-CBC (NIST Algorithm)
        OCTET STRING (16 byte) 6EE87374559F76BC362E29AE5A2E80FC
  OCTET STRING (192 byte) 50AF006CB4E8E42D9992155F9D749F35E7D4BA9D88975C70174157AC0D96909FDDF9F…

要获取工作且未加密的文件,请使用此OpenSSL命令将加密文件转换为未加密文件:

openssl pkcs8 -topk8 -nocrypt -in ecprivateencrypted.pem -out ecprivateunencrypted.pem 

我试着自己转换文件,但是我的OpenSSL拒绝了,因为密码长度太短了。

申颖逸
2023-03-14

我在第二个答案中回答,因为我的第一个答案不再适合这个问题,因为您编辑了您的问题并将私钥pem更改为未加密数据。

由于您的密钥是私钥的编码形式,因此它具有PKCS#8结构,因此任何读取器都能够识别密钥的类型和底层曲线,因此您无需使用ECPrivateKeySpec构建它。有一种更简单的方法可以使用此代码:

KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(pkcs8key);
return keyFactory.generatePrivate(privateKeySpec);

公钥也是如此,只需使用X509EncodedKeySpec(参见完整代码示例)。

添加了bytesFromKeyStrings-函数来将公钥的密钥数据转换成一个字节数组。

下面是一个完整的示例代码,用于读取私钥pem、对消息进行签名、读取公钥pem(源自私钥)并按照预期结果以“true”验证签名。

输出:

signatureVerified: true

安全警告:以下代码没有异常处理,仅用于教育目的:

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class MainSo {

    private final static String privatePem = "-----BEGIN PRIVATE KEY-----\r\n"
            + "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBBdsy5smSA2+DvnIdx\r\n"
            + "bqq6GwwHadEdtHqcKO9N8hB0/NKvFOCmHBSfBpYPgCWlybGhZANiAAQ0iyw2wPjs\r\n"
            + "zhale0mPkiCCTzcNzTW1g7zqUoN3XNuZbaK1FHhVVMsywUaS6MSUJI6r1QcUziMm\r\n"
            + "MWGYZUSSq4noniTDt8INj/ElndKhbh3oSCq3j1oKK9cYXi3uGuDFXks=\r\n"
            + "-----END PRIVATE KEY-----\r\n";
/*
Key Details:
   Type: EC
   Size (bits): 384
   Curve Name: secp384r1
   Curve OID: 1.3.132.0.34
   Public key (x):
348b2c36c0f8ecce16a57b498f9220824f370dcd35b583bcea5283775cdb996d
a2b514785554cb32c14692e8c494248e
   Public key (y):
abd50714ce2326316198654492ab89e89e24c3b7c20d8ff1259dd2a16e1de848
2ab78f5a0a2bd7185e2dee1ae0c55e4b
   Private key (d):
4176ccb9b26480dbe0ef9c87716eaaba1b0c0769d11db47a9c28ef4df21074fc
d2af14e0a61c149f06960f8025a5c9b1

Public Key in PEM Format:
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAENIssNsD47M4WpXtJj5Iggk83Dc01tYO8
6lKDd1zbmW2itRR4VVTLMsFGkujElCSOq9UHFM4jJjFhmGVEkquJ6J4kw7fCDY/x
JZ3SoW4d6Egqt49aCivXGF4t7hrgxV5L
-----END PUBLIC KEY-----
 */

    private final static String publicPem = "-----BEGIN PUBLIC KEY-----\n" +
            "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAENIssNsD47M4WpXtJj5Iggk83Dc01tYO8\n" +
            "6lKDd1zbmW2itRR4VVTLMsFGkujElCSOq9UHFM4jJjFhmGVEkquJ6J4kw7fCDY/x\n" +
            "JZ3SoW4d6Egqt49aCivXGF4t7hrgxV5L\n" +
            "-----END PUBLIC KEY-----";

    private static final BouncyCastleProvider BOUNCY_CASTLE_PROVIDER = new BouncyCastleProvider();

    private static byte[] bytesFromKeyStrings(String string) {
        string = string.replaceAll("-----BEGIN ENCRYPTED PRIVATE KEY-----", "");
        string = string.replaceAll("-----BEGIN PRIVATE KEY-----", "");
        string = string.replaceAll("-----BEGIN PUBLIC KEY-----", "");
        string = string.replaceAll("-----BEGIN EC PRIVATE KEY-----", "");
        string = string.replaceAll("-----END EC PRIVATE KEY-----", "");
        string = string.replaceAll("-----END ENCRYPTED PRIVATE KEY-----", "");
        string = string.replaceAll("-----END PRIVATE KEY-----", "");
        string = string.replaceAll("-----END PUBLIC KEY-----", "");
        string = string.replaceAll("\r", "");
        string = string.replaceAll("\n", "");
        return Base64.getDecoder().decode(string);
    }

    private static PrivateKey privateKeyFromBytes(byte[] pkcs8key) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
        Security.addProvider(BOUNCY_CASTLE_PROVIDER);
        KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
        PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(pkcs8key);
        return keyFactory.generatePrivate(privateKeySpec);
    }

    private static PublicKey publicKeyFromBytes(byte[] x509key) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
        Security.addProvider(BOUNCY_CASTLE_PROVIDER);
        KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(x509key);
        return keyFactory.generatePublic(publicKeySpec);
    }

    public static void main(String[] args) {
        System.out.println("https://stackoverflow.com/questions/65740255/scalar-is-not-in-the-interval-1-n-1-exception-when-signing-ecdsa-with-sha/65742506?noredirect=1#comment116237430_65742506");
        var content = new byte[100];
        try {
            // signature with private key
            var privateKey = privateKeyFromBytes(bytesFromKeyStrings(privatePem));
            var ecdsaSign = Signature.getInstance("SHA384withECDSA", BOUNCY_CASTLE_PROVIDER);
            ecdsaSign.initSign(privateKey, new SecureRandom());
            ecdsaSign.update(content);
            var signature = ecdsaSign.sign();

            // verification with the public key
            var publicKey = publicKeyFromBytes(bytesFromKeyStrings(publicPem));
            var ecdsaVerify = Signature.getInstance("SHA384withECDSA", BOUNCY_CASTLE_PROVIDER);
            ecdsaVerify.initVerify(publicKey);
            ecdsaVerify.update(content);
            boolean signatureVerified = ecdsaVerify.verify(signature);
            System.out.println("signatureVerified: " + signatureVerified);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
郦昆
2023-03-14

为什么它不起作用

OpenSSL支持的所有密钥格式不仅仅是原始密钥,还包括一些元数据;特别是,所有EC关键点都是meaningul,仅可用于关键点文件中包含的特定曲线。openssl pkcs8-topk8[-nocrypt]产生的两种格式是pkcs8中定义的未加密和加密格式,更方便地作为RFC5208获得,您可以在维基百科中轻松找到。在PEM类型“开始/结束私钥”和“开始/终止加密私钥”中使用这些格式在RFC7468第10节和第11节中进行了形式化,尽管OpenSSL早在几十年前就将其作为事实上的标准。

Michael Fehr的第一个答案向您展示了加密形式的分解,但即使是未加密的形式也仍然包含元数据,这些元数据使用secp384r1(也称为P-384曲线)将其识别为EC算法:

$ cat 65740255.clr
-----BEGIN PRIVATE KEY-----
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBBdsy5smSA2+DvnIdx
bqq6GwwHadEdtHqcKO9N8hB0/NKvFOCmHBSfBpYPgCWlybGhZANiAAQ0iyw2wPjs
zhale0mPkiCCTzcNzTW1g7zqUoN3XNuZbaK1FHhVVMsywUaS6MSUJI6r1QcUziMm
MWGYZUSSq4noniTDt8INj/ElndKhbh3oSCq3j1oKK9cYXi3uGuDFXks=
-----END PRIVATE KEY-----
$ openssl asn1parse <65740255.clr -i
    0:d=0  hl=3 l= 182 cons: SEQUENCE
    3:d=1  hl=2 l=   1 prim:  INTEGER           :00
    6:d=1  hl=2 l=  16 cons:  SEQUENCE
    8:d=2  hl=2 l=   7 prim:   OBJECT            :id-ecPublicKey
   17:d=2  hl=2 l=   5 prim:   OBJECT            :secp384r1
   24:d=1  hl=3 l= 158 prim:  OCTET STRING      [HEX DUMP]:30819B02010104304176CCB9B26480DBE0EF9C87716EAABA1B0C0769D11DB47A9C28EF4DF21074FCD2AF14E0A61C149F06960F8025A5C9B1A16403620004348B2C36C0F8ECCE16A57B498F9220824F370DCD35B583BCEA5283775CDB996DA2B514785554CB32C14692E8C494248EABD50714CE2326316198654492AB89E89E24C3B7C20D8FF1259DD2A16E1DE8482AB78F5A0A2BD7185E2DEE1AE0C55E4B

对于任何熟悉ASN.1的人来说,PKCS8中未加密的最后一个字段(依赖于算法的编码)本身就是一个ASN.1结构。RFC5915基于“SEC1”文档指定了X9类型EC privatekey的ASN.1结构(但不是更新的EC算法,如Bernstein等人的EdDSA)。解析我们看到它实际上包含实际的privatekey(即在Java S中通常表示为d的数字)和publickey(在Java W中通常表示为Q的点,以X9未压缩格式表示)(这在技术上是多余的,因为它可以从privatekey和曲线方程中重新计算出来):

$ openssl asn1parse <65740255.clr -i -strparse 27 -dump
    0:d=0  hl=3 l= 155 cons: SEQUENCE
    3:d=1  hl=2 l=   1 prim:  INTEGER           :01
    6:d=1  hl=2 l=  48 prim:  OCTET STRING
      0000 - 41 76 cc b9 b2 64 80 db-e0 ef 9c 87 71 6e aa ba   Av...d......qn..
      0010 - 1b 0c 07 69 d1 1d b4 7a-9c 28 ef 4d f2 10 74 fc   ...i...z.(.M..t.
      0020 - d2 af 14 e0 a6 1c 14 9f-06 96 0f 80 25 a5 c9 b1   ............%...
   56:d=1  hl=2 l= 100 cons:  cont [ 1 ]
   58:d=2  hl=2 l=  98 prim:   BIT STRING
      0000 - 00 04 34 8b 2c 36 c0 f8-ec ce 16 a5 7b 49 8f 92   ..4.,6......{I..
      0010 - 20 82 4f 37 0d cd 35 b5-83 bc ea 52 83 77 5c db    .O7..5....R.w\.
      0020 - 99 6d a2 b5 14 78 55 54-cb 32 c1 46 92 e8 c4 94   .m...xUT.2.F....
      0030 - 24 8e ab d5 07 14 ce 23-26 31 61 98 65 44 92 ab   $......#&1a.eD..
      0040 - 89 e8 9e 24 c3 b7 c2 0d-8f f1 25 9d d2 a1 6e 1d   ...$......%...n.
      0050 - e8 48 2a b7 8f 5a 0a 2b-d7 18 5e 2d ee 1a e0 c5   .H*..Z.+..^-....
      0060 - 5e 4b                                             ^K

另一种选择

如果您除了bcprov之外还使用BouncyCastle bcpkix jar,它还提供了直接读取(和写入)所有OpenSSL PEM格式的例程,包括PKCS8和OpenSSL的“传统”或“传统”算法特定格式 BEGIN/END EC PRIVATE KEY,这只是PEM包装中的SEC1。例如:
读取 JAVA 中格式为 PKCS1 的
RSA 私钥 从 RSA .pem 文件
获取私钥 使用 BouncyCastle 从文件中读取椭圆曲线私钥
如何从文件加载 RSA 私钥
(尽管其中一些是针对 RSA 的,但问题与 EC 相同)。

    String pk8e = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n"
            + "MIIBHDBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIG5SFWXEmy8QCAggA\r\n"
            + "MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBBu6HN0VZ92vDYuKa5aLoD8BIHA\r\n"
            + "UK8AbLTo5C2ZkhVfnXSfNefUup2Il1xwF0FXrA2WkJ/d+fokLijgkTyal43t8iMJ\r\n"
            + "ne3gOjYP8Q558x+4k4TAMWug0nDh9RPINMqABnhPkf5wyCCYI2RN2b3C4SZCBMQw\r\n"
            + "r+cwVgwiShhPHcuUM9BmFlt9eCr3kuFnfMxlvvpR482kIT+Q6+hZsyUL/oJjOVC9\r\n"
            + "R2S7AwiKH4BPj5TBjMKF4ZI5cS0DMXn1q3h21AUdMPUchX6itcDTfWvEIfTwpUr0\r\n"
            + "-----END ENCRYPTED PRIVATE KEY-----\r\n";
    String pk8u = "-----BEGIN PRIVATE KEY-----\r\n"
            + "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBBdsy5smSA2+DvnIdx\r\n"
            + "bqq6GwwHadEdtHqcKO9N8hB0/NKvFOCmHBSfBpYPgCWlybGhZANiAAQ0iyw2wPjs\r\n"
            + "zhale0mPkiCCTzcNzTW1g7zqUoN3XNuZbaK1FHhVVMsywUaS6MSUJI6r1QcUziMm\r\n"
            + "MWGYZUSSq4noniTDt8INj/ElndKhbh3oSCq3j1oKK9cYXi3uGuDFXks=\r\n"
            + "-----END PRIVATE KEY-----\r\n";
    String trad = "-----BEGIN EC PRIVATE KEY-----\r\n"
            + "MIGkAgEBBDBBdsy5smSA2+DvnIdxbqq6GwwHadEdtHqcKO9N8hB0/NKvFOCmHBSf\r\n"
            + "BpYPgCWlybGgBwYFK4EEACKhZANiAAQ0iyw2wPjszhale0mPkiCCTzcNzTW1g7zq\r\n"
            + "UoN3XNuZbaK1FHhVVMsywUaS6MSUJI6r1QcUziMmMWGYZUSSq4noniTDt8INj/El\r\n"
            + "ndKhbh3oSCq3j1oKK9cYXi3uGuDFXks=\r\n"
            + "-----END EC PRIVATE KEY-----\r\n";
    
    @SuppressWarnings("resource") // should use try-resources or similar
    Object o1 = new PEMParser (new StringReader (pk8e)).readObject();
    PrivateKey k1 = new JcaPEMKeyConverter().getPrivateKey(
            ((org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo)o1).decryptPrivateKeyInfo(
                    new JceOpenSSLPKCS8DecryptorProviderBuilder().build(/*password*/"".toCharArray()) ));
    System.out.println ( ((java.security.interfaces.ECPrivateKey)k1).getS() .toString(16));
    
    @SuppressWarnings("resource") // should use try-resources or similar
    Object o2 = new PEMParser (new StringReader (pk8u)).readObject();
    PrivateKey k2 = new JcaPEMKeyConverter().getPrivateKey((PrivateKeyInfo)o2);
    System.out.println ( ((java.security.interfaces.ECPrivateKey)k2).getS() .toString(16));
    
    @SuppressWarnings("resource") // should use try-resources or similar
    Object o3 = new PEMParser (new StringReader (trad)).readObject();
    PrivateKey k3 = new JcaPEMKeyConverter().getKeyPair((PEMKeyPair)o3).getPrivate();
    System.out.println ( ((java.security.interfaces.ECPrivateKey)k3).getS() .toString(16));

->
4176ccb9b26480dbe0ef9c87716eaaba1b0c0769d11db47a9c28ef4df21074fcd2af14e0a61c149f06960f8025a5c9b1
4176ccb9b26480dbe0ef9c87716eaaba1b0c0769d11db47a9c28ef4df21074fcd2af14e0a61c149f06960f8025a5c9b1
4176ccb9b26480dbe0ef9c87716eaaba1b0c0769d11db47a9c28ef4df21074fcd2af14e0a61c149f06960f8025a5c9b1

并且该(十六进制)数字是“原始”私钥,这是您可以在ECPrivateKeySpec中为您发布的方法放置的值(作为正BigInteger)。(我不得不使一些名称符合包条件,因为在我的开发环境中,我有冲突的导入;你可能不需要它。

 类似资料:
  • 我正在使用C#和.NET4.7使用BouncyCastle进行签名验证。 我在这里跟随一个回答,所以在这里解释了使用SHA-256withECDSA的验证过程。 因此,我使用两种方法验证签名的代码在下面的代码片段中运行良好。 我正在尝试将其调整到我的用例,该用例正在使用ECDSA签名验证SHA-384。我发现的唯一区别是密钥长度不同。对于 SHA-256 与 ECDSA,使用的公钥长度转换为 64

  • 问题内容: 我正在尝试从字符串计算SHA-1哈希,但是当我使用php的sha1函数计算字符串时,我得到的东西与在C#中尝试时有所不同。我需要C#计算与PHP相同的字符串(因为php的字符串是由我无法修改的第三方计算的)。如何获取C#以生成与PHP相同的哈希值?谢谢!!! 字串= s934kladfklada@a.com C#代码(生成d32954053ee93985f5c3ca2583145668

  • 两者的区别是什么 和 ? 第一个语句的输出是 [0 0…n次] 而第二个是 ([0] [0] .... n行)

  • 我正在将我们的DAO从使用Hibernate Criteria API迁移到JPA Criteria API。我有一个包含多个的类: 在查询中,我使用的是JoinType。左键以消除默认生成的交叉连接: 我得到了正确的结果,所有的A和B记录都得到了正确的检索。然而,在迁移之后,我遇到了一个问题:尽管在生成的查询中使用了左外连接,但所有的记录都是逐个检索的。以前(使用Hibernate Criter

  • 问题内容: 我在sql中有一个普遍的疑问。实际上,“ Top 1 1”将做什么?以下查询的含义是什么? SQL Server查询中选择“ TOP 1 1”和“ SELECT 1”之间的区别是什么? 问题答案: 表示在结果集中选择第一条记录 平均值返回1作为结果集 表示如果条件为true,并且从select返回了任何行,则仅返回顶部行,并且仅返回该行的整数(仅返回整数1就没有数据)。

  • 问题内容: 为什么呢?如我所料是0。 问题答案: 所有移位都针对整数进行mod 32,对long进行mod 64。 从规范的第15.19节开始: 如果左侧操作数的提升类型为,则仅将右侧操作数的最低5位用作移位距离。就像右侧操作数受到掩码值0x1f的按位逻辑AND运算符&(§15.22.1)一样。因此,实际使用的移动距离始终在0到31(含)范围内。 如果左侧操作数的提升类型为,则仅将右侧操作数的六个