我正在尝试使用.NET(CNG提供商)的现有ECDSA密钥,以便使用Bouncy Castle对数据进行签名,然后在两种签名格式(P1363和ASN.1)之间进行转换。然而,我总是得到不同的签名。我不太确定转换是否不正确,或者我是否使用了不正确的方法来使用Bouncy Castle读取.NET密钥。
var ecdsaKey = new ECDsaCng(cngKey);
var testData = Encoding.UTF8.GetBytes("test");
var akPrivate = PrivateKeyFactory.CreateKey(cngKey.Export(CngKeyBlobFormat.Pkcs8PrivateBlob));
var bcSigner = SignerUtilities.GetSigner("SHA256withECDSA");
bcSigner.Init(true, akPrivate);
bcSigner.BlockUpdate(testData, 0, testData.Length);
var bcSignature = bcSigner.GenerateSignature();
var asn1Stream = new Asn1InputStream(bcSignature);
var bcDerSequence = ((DerSequence) asn1Stream.ReadObject());
var bcR = ((DerInteger) bcDerSequence[0]).PositiveValue;
var bcS = ((DerInteger) bcDerSequence[1]).PositiveValue;
var msSignature = ecdsaKey.SignData(testData, HashAlgorithmName.SHA256);
// P1363 to ASN.1
var msR = new BigInteger(1, msSignature.Take(msSignature.Length/2).ToArray());
var msS = new BigInteger(1, msSignature.Skip(msSignature.Length/2).ToArray());
var msRDer = new DerInteger(msR);
var msSDer = new DerInteger(msS);
var msDerSequence = new DerSequence(msRDer, msSDer).GetDerEncoded();
由于某些原因,bcR
和msR
已经不同,我假设问题甚至可能在转换之前就出现了。我已经看过许多StackOverflow文章(例如,使用Crypto?将签名从P1363转换为ASN.1/DER格式,用C#中的Bouncy Castle验证ECDSA签名,用C#中的Boundy Castle检验ECDSA签字),但似乎做得不对。任何提示都将不胜感激!
不幸的是,我从未解决过这个问题。然而,我为我的特定用例提出了一种不同的方法。我的用例是读取Kotlin中的Pkcs8PrivateBlob.NET密钥,并生成/验证与.NET中生成的签名兼容的签名(即.NET中产生的签名在Kotlin应有效,反之亦然)。我将我的方法张贴在这里以供参考,但请注意,它不是原始问题的解决方案。这也不是一个非常优雅的解决方案,很可能也不是最简单的解决方案。但我必须以某种方式让它工作。
较新的JDK版本支持P1363签名格式,这意味着至少我只需将密钥块转换成Java可读的格式,即PKCS#8。尽管如此,我还是使用BouncyCastle在Kotlin中创建了最初的keypair。
在 C 中将私钥 blob 转换为 PKCS#8#
internal enum KeyBlobMagicNumber : int
{
BCRYPT_DSA_PUBLIC_MAGIC = 0x42505344,
BCRYPT_DSA_PRIVATE_MAGIC = 0x56505344,
BCRYPT_DSA_PUBLIC_MAGIC_V2 = 0x32425044,
BCRYPT_DSA_PRIVATE_MAGIC_V2 = 0x32565044,
BCRYPT_ECDH_PUBLIC_P256_MAGIC = 0x314B4345,
BCRYPT_ECDH_PRIVATE_P256_MAGIC = 0x324B4345,
BCRYPT_ECDH_PUBLIC_P384_MAGIC = 0x334B4345,
BCRYPT_ECDH_PRIVATE_P384_MAGIC = 0x344B4345,
BCRYPT_ECDH_PUBLIC_P521_MAGIC = 0x354B4345,
BCRYPT_ECDH_PRIVATE_P521_MAGIC = 0x364B4345,
BCRYPT_ECDH_PUBLIC_GENERIC_MAGIC = 0x504B4345,
BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC = 0x564B4345,
BCRYPT_ECDSA_PUBLIC_P256_MAGIC = 0x31534345,
BCRYPT_ECDSA_PRIVATE_P256_MAGIC = 0x32534345,
BCRYPT_ECDSA_PUBLIC_P384_MAGIC = 0x33534345,
BCRYPT_ECDSA_PRIVATE_P384_MAGIC = 0x34534345,
BCRYPT_ECDSA_PUBLIC_P521_MAGIC = 0x35534345,
BCRYPT_ECDSA_PRIVATE_P521_MAGIC = 0x36534345,
BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC = 0x50444345,
BCRYPT_ECDSA_PRIVATE_GENERIC_MAGIC = 0x56444345,
BCRYPT_RSAPUBLIC_MAGIC = 0x31415352,
BCRYPT_RSAPRIVATE_MAGIC = 0x32415352,
BCRYPT_RSAFULLPRIVATE_MAGIC = 0x33415352,
BCRYPT_KEY_DATA_BLOB_MAGIC = 0x4d42444b,
}
[StructLayout(LayoutKind.Sequential)]
internal struct BCRYPT_ECCKEY_BLOB
{
internal KeyBlobMagicNumber Magic;
internal int cbKey;
}
// ===== THE CONVERSION PROCESS =====
byte[] d;
byte[] blobBytes = // store Pkcs8PrivateBlob here
// Parse the binary blob into a BCRYPT_ECCKEY_BLOB structure
// (see https://docs.microsoft.com/en-gb/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_ecckey_blob?redirectedfrom=MSDN)
unsafe
{
fixed (byte* pBlob = blobBytes)
{
BCRYPT_ECCKEY_BLOB* pBcryptBlob = (BCRYPT_ECCKEY_BLOB*) pBlob;
var headerSize = sizeof(BCRYPT_ECCKEY_BLOB);
var keyData = blobBytes.Skip(headerSize).ToArray();
d = keyData.Skip(pBcryptBlob->cbKey * 2).ToArray();
// The values in the blob are big-endian. Check if we need to reverse them to little-endian
if (BitConverter.IsLittleEndian)
{
d = Arrays.Reverse(d);
}
// Append 0 to mark the data as unsigned as per the documentation of System.Numerics.BigInteger
var unsignedByteData = d.Concat(new byte[] {0}).ToArray();
var dValue = new System.Numerics.BigInteger(unsignedByteData);
// Create a BouncyCastle BigInteger from the string representation to make sure that we use the
// same endianess and sign
var dValueBC = new BigInteger(dValue.ToString());
var ecDomainParameters = TlsEccUtilities.GetParametersForNamedCurve(NamedCurve.secp384r1);
// Build a private key from the parsed d value
var privateKey = new ECPrivateKeyParameters(dValueBC, ecDomainParameters);
// Export the private key in PKCS#8 format
var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKey);
var result = privateKeyInfo.GetDerEncoded();
}
}
使用BouncyCastle在静态编程语言中从PKCS#8私钥创建密钥对
class KeyConverter : IKeyConverter {
init {
Security.addProvider(BouncyCastleProvider())
}
override fun getKeyPair(pkcs8Base64Key: String): KeyPair {
val decoder = Base64.getDecoder()
val keyBytes = decoder.decode(pkcs8Base64Key)
val pkcS8EncodedKeySpec = PKCS8EncodedKeySpec(keyBytes)
val defaultKeyFactory = KeyFactory.getInstance("EC", "BC")
val privateKey = defaultKeyFactory.generatePrivate(pkcS8EncodedKeySpec) as ECPrivateKey
val publicKey = publicKeyFromPrivateKey(privateKey)
return KeyPair(publicKey, privateKey)
}
private fun publicKeyFromPrivateKey(key: ECPrivateKey): PublicKey {
val bcKeyFactory = KeyFactory.getInstance("EC", "BC")
val ecParameterSpec = ECNamedCurveTable.getParameterSpec("secp384r1")
val Q = ecParameterSpec.g.multiply(JCEECPrivateKey(key).d)
val publicKeySpec = ECPublicKeySpec(Q, ecParameterSpec)
return bcKeyFactory.generatePublic(publicKeySpec)
}
}
使用密钥对在Kotlin中创建/验证P1363签名
class DefaultCryptoProvider(private val keyPair: KeyPair) {
private val randomSource: SecureRandom = SecureRandom()
override fun signData(data: ByteArray): ByteArray {
val signature = Signature.getInstance("SHA256withECDSAinP1363Format")
signature.initSign(keyPair.private)
signature.update(data)
return signature.sign()
}
override fun verifyData(data: ByteArray, signatureData: ByteArray): Boolean {
val signature = Signature.getInstance("SHA256withECDSAinP1363Format")
signature.initVerify(keyPair.public)
signature.update(data)
return signature.verify(signatureData)
}
}
希望它至少能帮助有类似问题的人。
我的项目正在对来自某些第三方软件的某些数据集进行签名验证。使用的签名算法是 。当我使用SDK附带的标准SUN加密提供程序时,一切都很顺利。最近我切换到了Bouncy Castle 1.50,之后,一些以前(即SUN提供者)进行验证的数据集开始失败,而其余的仍然被验证正常。 我探索了两个提供程序的源代码,结果发现SDK的默认提供程序对格式错误的签名有某种保护(同时能够恢复),而Bouncy Cast
我需要用Java中的Bouncy Castle创建一个自签名X509证书,但我尝试包含的每个类都不推荐使用。我该怎么解决这个问题?还有其他课程吗?谢谢
我正在开发一个功能来对某些内容进行数字签名。我有一个带有私钥的有效证书。如何使用私钥和充气城堡进行数字签名? 我尝试了以下方法,但想要一些正确的方法来实现同样的使用充气城堡: 谢谢!
有人能解释一下为什么这段代码在解密密钥时会在最后一行抛出吗? 以下是来自https://stackoverflow.com/a/27886397/66722对于使用OAEP的RSA也是如此? “RSA/ECB/PKCS1Padding”实际上没有实现ECB模式加密。它应该被称为“RSA/None/PKCS1Padding”,因为它只能用于加密单个明文块(或者实际上是一个密钥)。这只是Sun/Ora
首先,我需要在C#代码中复制功能。我设法将私钥加载到并调用,但得到的结果与不同。 据我所知,根据这篇文章和这个RFC,当被调用时,没有,openssl不会用digest函数标识符捆绑数据,并跳过ASN.1编码。这意味着对原始数据进行填充和加密。这个工具似乎确认,解密签名看起来像填充的明文数据。 那么用C#怎么做呢?中的所有函数都要求在加密之前指定哈希算法和编码签名。我是否遗漏了什么,或者我将不得不
问题内容: 如何使用MapKit从坐标获取地址? 当在地图上长按时,我得到了以下代码: 我想用完整的地址(街道,城市,邮政编码,国家)打印。 问题答案: SWIFT 4.2:编辑 框架确实提供了一种从坐标获取地址详细信息的方法。 您需要使用地图套件的 反向地理编码 。类用于从地址获取位置,并从位置(坐标)获取地址。该方法将从坐标返回地址详细信息。 此方法接受作为参数并返回,其中包含地址字典。 所以