- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想使用 SHA-384 生成 384 位椭圆曲线签名,以生成 key ,我通过查看此 SO Generate EC KeyPair from OpenSSL command line 运行以下步骤
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
当我被要求输入密码时,我按下了回车键(因为我不想拥有受密码保护的 key )。
然后我为我的 JRE 14 下载了 bcprov-jdk15on-168.jar Bouncy CaSTLe lib,并将其添加到我的类路径中。并制作了小测试应用,将这些键的内容直接复制到java源代码中就可以了。
做了一个简单的剥离方法来去除key的'text'部分并解码它的base64内容:
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;
}
然后从这些字节中生成一个 PrivateKey:
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);
}
但是当我要使用 PrivateKey 来签署消息(在本例中是零数组)时,我得到了异常:
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,我们需要将私钥乘以某个随机值,那么我将提供它 secureRandom。奇怪的是,当我没有尝试读取 key 并使用 KeyPairGenerator.getInstance("EC") 动态生成它们(没有 bouncycaSTLe 库)时,我之前的尝试然后这些生成的 key 可用于签署消息而无需异常,我单独验证了生成的签名是正确的。
我生成的 key 很糟糕,还是有其他方法可以提供乘数常数,所以它不会尝试直接用私钥签名并给我异常(exception)?
还是我错过了什么傻事?
下面是我的可以重现异常的测试应用程序的完整列表:
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();
}
}
}
编辑:更新了示例(之前我使用的是加密私钥)
最佳答案
为什么它不起作用
OpenSSL 支持的所有 key 格式不仅仅是原始 key ,还包括一些元数据;特别是所有 EC key 都是有意义的,并且仅对包含在 key 文件中的特定曲线可用。 openssl pkcs8 -topk8 [-nocrypt]
产生的两种格式是 unencrypted和 encrypted PKCS8 中定义的格式,更方便地使用 RFC5208,您可以在 wikipedia 中轻松找到它.这些格式在 PEM 类型“BEGIN/END PRIVATE KEY”和“BEGIN/END ENCRYPTED PRIVATE KEY”中的使用在 RFC7468 section 10 中正式化。和 section 11尽管 OpenSSL 早在几十年前就将它们作为事实上的标准。
Michael Fehr 的第一个答案向您展示了加密形式的分割,但即使是未加密的形式仍包含元数据,将其识别为使用 secp384r1 aka 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 私钥的 ASN.1 结构(但不是像 Bernstein 等人的 EdDSA 这样的较新的 EC 算法)。解析我们看到它实际上包含实际的私钥(即数字通常表示为 d 但在 Java S 中)和公钥(一个点通常表示为 Q 但在 Java W 中,采用 X9 未压缩格式)(这在技术上是多余的,因为它可以由私钥和曲线方程重新计算):
$ 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。参见例如:
Read RSA private key of format PKCS1 in JAVA
Get a PrivateKey from a RSA .pem file
Reading elliptic curve private key from file with BouncyCastle
How to Load RSA Private Key From File
(虽然其中一些适用于 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
) . (我必须使一些名称符合包资格,因为在我的开发环境中,我的导入有冲突;你可能不需要。)
关于java - 使用 SHA-384 签署 ECDSA 时出现 "Scalar is not in the interval [1, n - 1]"异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65740255/
安全服务 API 似乎不允许我直接计算哈希。有很多公共(public)领域和自由许可的版本可用,但如果可能的话,我宁愿使用系统库实现。 可以通过 NSData 或普通指针访问数据。 哈希的加密强度对我
我有一堆大对象,以及它们的结构和它们的向量。有时检查复合对象的完整性很重要;为此,我正在使用对象的 Sha256“签名”。 至少有两种方法可以定义复合对象的签名:通过计算组件串联的sha,或者通过计算
研究了一个 cpu 矿工的源代码,我发现了这段代码: work->data[20] = 0x80000000; 好吧,我问了编码,他的回答是: “这些值是标准 SHA-2 填充的一部分” 谷歌搜索“s
您是否需要许可证才能将 SHA-1 或 SHA-2 用于商业目的? 最佳答案 它最初由 NSA 为安全 DSA 加密创建,然后被 NIST 采用以维护算法的所有方面以及 SHA(2 和 3)。 这是一
谁能解释一下 SHA-256 和 RIPEMD-160,哪种算法通常更快,性能和空间比较是什么(如果有)?我所说的空间比较并不是指 160 位和 256 位,而是指冲突频率、生产环境中空间要求的差异。
我对 SHA-2 和 SHA-256 之间的区别有点困惑,并且经常听到它们互换使用。我认为 SHA-2 是哈希算法的“家族”,而 SHA-256 是该家族中的特定算法。任何人都可以消除困惑。 最佳答案
我正在尝试从 SHA-1 更改为 SHA-512 以获得更好的安全性,但我不完全清楚如何进行更改。 这是我使用 SHA-1 的方法: public static String sha1Convert(
在我的 C# 应用程序中,我使用 RSA 对文件进行签名,然后再由上传者上传到我公司的数据库中,在这里我必须选择 SHA-1 或 SHA-2 来计算哈希值。与编程中的任何其他组件一样,我知道必须有一个
我正在研究 SHA1 、 SHA-256 、 SHA-512 在不同处理器上的速度(计算哈希的时间) 这些散列算法可以分解为跨多个核心/线程运行吗? 最佳答案 如果您想将计算单个哈希的执行并行化(无论
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题? Update the question所以它是on-topic对于堆栈溢出。 9年前关闭。 Improve this que
这个问题在这里已经有了答案: SHA2 password hashing in java (4 个答案) 关闭 9 年前。 我需要计算文件的 SHA-2 或 SHA-3。我没有提交任何代码示例来说明
在我的应用中,之前开发者已经使用openssl version 1.0.1e [#include openssl/sha.h]并且已经使用了函数 unsigned char *SHA(const un
我正在尝试实现 SHA-2加密而不是 SHA-1 . 为此,我知道这两种哈希算法之间的位数不同,这让我很困惑。 如何实现这一目标以及我需要在哪些部分进行必要的更改? 我可以使用来自 Java、Pyth
我目前正在使用 SHA-1。我像下面的代码一样使用它,但我想将它更改为 SHA-256。 public String sha1Encrypt(String str) { if(str == nul
我想将一些 Java 代码转换为 C#。 Java 代码: private static final byte[] SALT = "NJui8*&N823bVvy03^4N".getBytes()
我的程序使用 SHA-1 证书进行 SSL 连接。 SHA-2 证书现在已被一些网络服务(Gmail)广泛使用。这会导致在电子邮件通知设置期间阻止与 SMTP 服务器的传入连接。 为了发送电子邮件,我
我在提交中生成差异/更改,以便我可以将其上传到 ReviewBoard。 我使用了“git show d9f7121e8ebd4d1f789dab9f8214ada2h480b9cf”。它给了我 di
我刚刚从这个 HN-post 了解到 git 正在转向新的散列算法(从 SHA-1 到 SHA-256 ) 我想知道是什么让 SHA-256 最适合 git 的用例。 是否有任何/许多强有力的技术原因
是的,我需要降级到 SHA-1 以增加对项目中旧浏览器的兼容性。 有没有办法做到这一点? 我正在使用 Linux Centos 6.5 和 Apache/2.2.15。 我有 3 个文件: SSLCe
在 TLS1.1 和 TLS1.2 中,Cipher(rsa-with-aes-128-cbc-sha) 将使用哪个 Digest(SHA1 或 SHA256)? 最佳答案 根据官方openssl w
我是一名优秀的程序员,十分优秀!