嗨,我正在使用代码,您能否让我知道为什么签名验证无效?
Java签署者将 BouncyCastleProvider 与 SHA1withRSA 结合 使用,这是dotnet验证代码…。
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string pubkey = @"MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMf54mcK3EYJn9tT9BhRoTX+8AkqojIyeSfog9ncYEye0VXyBULGg2lAQsDRt8lZsvPioORZW7eB6IKawshoWUsCAwEAAQ==";
String signature = "770bb2610bf6b2602ce2b3ad8489054f4ed59c9b0c9299327f76ecbc60a8bb9a725cfae901fc189d4bafcf73a2f4aed8dffe9842f7b6196ddfcd040c7271c7ca";
String signData = "C2:AE:D6:2B:DF:A4";
byte[] expectedSig = System.Convert.FromBase64String(signature);
byte[] baKey = System.Convert.FromBase64String(pubkey);
byte[] data = Encoding.UTF8.GetBytes(signData);
//Console.WriteLine(p.VerifyData(data, new SHA1CryptoServiceProvider(), expectedSig));
/* Init alg */
ISigner signer = SignerUtilities.GetSigner("SHA1withRSA");
/* Populate key */
signer.Init(false, DecodeX509PublicKey2(baKey));
/* Calculate the signature and see if it matches */
signer.BlockUpdate(data, 0, data.Length);
Console.WriteLine(signer.VerifySignature(expectedSig));
Console.In.ReadLine();
}
public static RsaKeyParameters DecodeX509PublicKey2(byte[] x509key)
{
byte[] SeqOID = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
MemoryStream ms = new MemoryStream(x509key);
BinaryReader reader = new BinaryReader(ms);
if (reader.ReadByte() == 0x30)
ReadASNLength(reader); //skip the size
else
return null;
int identifierSize = 0; //total length of Object Identifier section
if (reader.ReadByte() == 0x30)
identifierSize = ReadASNLength(reader);
else
return null;
if (reader.ReadByte() == 0x06) //is the next element an object identifier?
{
int oidLength = ReadASNLength(reader);
byte[] oidBytes = new byte[oidLength];
reader.Read(oidBytes, 0, oidBytes.Length);
if (oidBytes.SequenceEqual(SeqOID) == false) //is the object identifier rsaEncryption PKCS#1?
return null;
int remainingBytes = identifierSize - 2 - oidBytes.Length;
reader.ReadBytes(remainingBytes);
}
if (reader.ReadByte() == 0x03) //is the next element a bit string?
{
ReadASNLength(reader); //skip the size
reader.ReadByte(); //skip unused bits indicator
if (reader.ReadByte() == 0x30)
{
ReadASNLength(reader); //skip the size
if (reader.ReadByte() == 0x02) //is it an integer?
{
int modulusSize = ReadASNLength(reader);
byte[] modulus = new byte[modulusSize];
reader.Read(modulus, 0, modulus.Length);
if (modulus[0] == 0x00) //strip off the first byte if it's 0
{
byte[] tempModulus = new byte[modulus.Length - 1];
Array.Copy(modulus, 1, tempModulus, 0, modulus.Length - 1);
modulus = tempModulus;
}
Array.Reverse(modulus); //convert to big-endian
if (reader.ReadByte() == 0x02) //is it an integer?
{
int exponentSize = ReadASNLength(reader);
byte[] exponent = new byte[exponentSize];
reader.Read(exponent, 0, exponent.Length);
Array.Reverse(exponent); //convert to big-endian
//RSAParameters RSAKeyInfo = new RSAParameters();
//RSAKeyInfo.Modulus = modulus;
//RSAKeyInfo.Exponent = exponent;
return MakeKey(BitConverter.ToString(modulus).Replace("-", string.Empty), BitConverter.ToString(exponent).Replace("-", string.Empty), false);
}
}
}
}
return null;
}
public static RsaKeyParameters MakeKey(String modulusHexString, String exponentHexString, bool isPrivateKey)
{
var modulus = new Org.BouncyCastle.Math.BigInteger(modulusHexString, 16);
var exponent = new Org.BouncyCastle.Math.BigInteger(exponentHexString, 16);
return new RsaKeyParameters(isPrivateKey, modulus, exponent);
}
public static RSACryptoServiceProvider DecodeX509PublicKey(byte[] x509key)
{
byte[] SeqOID = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
MemoryStream ms = new MemoryStream(x509key);
BinaryReader reader = new BinaryReader(ms);
if (reader.ReadByte() == 0x30)
ReadASNLength(reader); //skip the size
else
return null;
int identifierSize = 0; //total length of Object Identifier section
if (reader.ReadByte() == 0x30)
identifierSize = ReadASNLength(reader);
else
return null;
if (reader.ReadByte() == 0x06) //is the next element an object identifier?
{
int oidLength = ReadASNLength(reader);
byte[] oidBytes = new byte[oidLength];
reader.Read(oidBytes, 0, oidBytes.Length);
if (oidBytes.SequenceEqual(SeqOID) == false) //is the object identifier rsaEncryption PKCS#1?
return null;
int remainingBytes = identifierSize - 2 - oidBytes.Length;
reader.ReadBytes(remainingBytes);
}
if (reader.ReadByte() == 0x03) //is the next element a bit string?
{
ReadASNLength(reader); //skip the size
reader.ReadByte(); //skip unused bits indicator
if (reader.ReadByte() == 0x30)
{
ReadASNLength(reader); //skip the size
if (reader.ReadByte() == 0x02) //is it an integer?
{
int modulusSize = ReadASNLength(reader);
byte[] modulus = new byte[modulusSize];
reader.Read(modulus, 0, modulus.Length);
if (modulus[0] == 0x00) //strip off the first byte if it's 0
{
byte[] tempModulus = new byte[modulus.Length - 1];
Array.Copy(modulus, 1, tempModulus, 0, modulus.Length - 1);
modulus = tempModulus;
}
Array.Reverse(modulus); //convert to big-endian
if (reader.ReadByte() == 0x02) //is it an integer?
{
int exponentSize = ReadASNLength(reader);
byte[] exponent = new byte[exponentSize];
reader.Read(exponent, 0, exponent.Length);
Array.Reverse(exponent); //convert to big-endian
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = new RSAParameters();
RSAKeyInfo.Modulus = modulus;
RSAKeyInfo.Exponent = exponent;
RSA.ImportParameters(RSAKeyInfo);
return RSA;
}
}
}
}
return null;
}
public static int ReadASNLength(BinaryReader reader)
{
//Note: this method only reads lengths up to 4 bytes long as
//this is satisfactory for the majority of situations.
int length = reader.ReadByte();
if ((length & 0x00000080) == 0x00000080) //is the length greater than 1 byte
{
int count = length & 0x0000000f;
byte[] lengthBytes = new byte[4];
reader.Read(lengthBytes, 4 - count, count);
Array.Reverse(lengthBytes); //
length = BitConverter.ToInt32(lengthBytes, 0);
}
return length;
}
}
}
用于签署签名数据的Java代码:
private static final java.security.Signature signer;
static final String transformation = "RSA/ECB/PKCS1Padding";
static {
try {
signer = java.security.Signature.getInstance("SHA1withRSA");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
static String sign(String clearText) {
String signed = null;
try {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
byte[] data = clearText.getBytes("UTF-8");
signer.initSign(getPrivateKey());
signer.update(data);
byte[] digitalSignature = signer.sign();
//--toHex
signed = org.apache.commons.codec.binary.Hex.encodeHexString(digitalSignature);
} catch (Exception e) {
e.printStackTrace();
}
return signed;
}
KeyPair generateKeyPair() {
KeyPair kp = null;
// Generate a key-pair
KeyPairGenerator kpg;
SecureRandom secureRandom;
try {
kpg = KeyPairGenerator.getInstance("RSA");
secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN");
secureRandom.setSeed(secureRandomSeed);
kpg.initialize(512, secureRandom);
kp = kpg.generateKeyPair();
} catch (Exception e) {
e.printStackTrace();
}
return kp;
}
这是C#中用于签名和验证的代码:
static void test3()
{
AsymmetricCipherKeyPair keys = generateNewKeys();
/* Init alg */
ISigner sig = SignerUtilities.GetSigner("SHA1withRSA");
/* Populate key */
sig.Init(true, keys.Private);
/* Get the bytes to be signed from the string */
var bytes = Encoding.UTF8.GetBytes(signData);
/* Calc the signature */
sig.BlockUpdate(bytes, 0, bytes.Length);
byte[] signature = sig.GenerateSignature();
/* Base 64 encode the sig so its 8-bit clean */
var signedString = Convert.ToBase64String(signature);
Console.WriteLine(signedString);
string expectedSignature = signedString;
/* Init alg */
ISigner signer = SignerUtilities.GetSigner("SHA1withRSA");
/* Populate key */
signer.Init(false, keys.Public);
/* Get the signature into bytes */
var expectedSig = Convert.FromBase64String(expectedSignature);
/* Get the bytes to be signed from the string */
var msgBytes = Encoding.UTF8.GetBytes(signData);
/* Calculate the signature and see if it matches */
signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
/*Verify*/
bool result= signer.VerifySignature(expectedSig);
Console.WriteLine(result);
}
这里有几个问题。
String signature = "770bb ... 1c7ca";
...
byte[] expectedSig = System.Convert.FromBase64String(signature);
您正在对签名进行Base64解码,但不是Base64编码,而是十六进制编码。
第二个问题是DecodeX509PublicKey
方法中的(这是我的错误,因为我在另一个答案中提供了此代码。)特定的问题行是
Array.Reverse(modulus); //convert to big-endian
和
Array.Reverse(exponent); //convert to big-endian
我反复读到ASN.1和.Net
API的密钥使用相反的字节序,因此,我给人的印象是,需要对此字节序进行反转以解决此问题。(确实,我确实应该像签名验证一样进行测试,而不是仅仅查看内存中的键值>。<)无论如何,删除这些行,解决编码问题,然后您的签名将正确验证(已成功测试)使用您的示例数据以及我自己的示例数据)。
另外,sign
方法中的这一行不太正确:
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
到代码中的那一点时,该signer
对象已经使用默认提供程序实例化了。同样,您不需要每次想要对某些数据进行签名时都添加Bouncy
Castle提供程序,它实际上只会在您第一次进行此调用时第一次添加该提供程序,并且在所有后续调用中都将忽略它。
此外,该signer
对象已被解密static
,但是您对它的使用不是线程安全的。
您更可能想做的是在静态块中添加提供程序,然后使用Bouncy Castle提供程序显式实例化签名者。如果您未明确指定Bouncy
Castle作为提供程序(或使用来将Bouncy Castle添加为最高优先级insertProviderAt
),则将使用默认提供程序。
static {
try {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
} catch (Exception e) {
e.printStackTrace();
}
}
...
String signed = null;
try {
java.security.Signature signer = java.security.Signature.getInstance("SHA1withRSA", "BC");
byte[] data = clearText.getBytes("UTF-8");
signer.initSign(getPrivateKey());
...
我创建并使用RSA公钥/私钥来加密/解密一些消息,我将它们作为字符串存储到sharedpreferences中,当我需要它们时,我从字符串创建它们。一切工作都很完美,但是将我的私钥作为字符串存储在sharedpreferences中是否安全。带着这个问题: SharedPreferences模式_Private安全性 我了解到,有人可以访问我的sharedpreferences并可以从字符串生成我
问题内容: 我只有一个PublicKey字符串,如何获得PublicKey指纹?我有一些想法表https://go- review.googlesource.com/c/crypto/+/32814 ,但是我不知道如何 实现ssh.PublicKey接口。 问题答案: 您可能要使用ssh包中的ssh.ParseAuthorizedKey来加载密钥: https://godoc.org/golang
我正在研究RxJava,为此我正在使用SQLite,编写一个帮助类,以便更容易地处理异步ContentResolver查询。例如,这是方法: 其中是接口: 我读过有关调度器的文档,但我不太确定是否是正确的选择。 如果我想为基本的操作实现类似的操作,我应该选择哪种调度程序?或,我会坚持使用...但不确定。 提前道谢。 万事如意,卢卡
我不知道如何在我们的VPC中提供对AWS Lambda的出站Internet访问,同时还具有Internet网关以支持对我们VPC中某些资源的入站访问(从Internet)。 从下面提供的文档中,我了解到我们需要创建一个私有和公共子网(使用NAT),并且有一个路由表指向IGW,另一个指向NAT。 https://aws.amazon.com/premiumsupport/knowledge-cen
问题内容: 您好,我正在尝试在我的应用程序中实现加密。我在前端使用angular(angular-4),在后端使用node js。通过socket.io通过自定义命令进行通信。但基本上,我坚持要在客户端中找到用于RSA加密的适当库。客户端将首先向服务器请求RSA公钥。服务器用密钥响应,但是现在我找不到任何适合使用此公共密钥通过RSA加密数据的库。我已经尝试过node- rsa。以下是代码sn 但我
问题内容: 有人可以向我解释为什么解密密钥时此代码会出现在最后一行吗? 来自OAEP的RSA的http://codingdict.com/questions/131368中的以下声明也适用吗? 实际上,“ RSA / ECB / PKCS1Padding”未实现ECB模式加密。它应该被称为“ RSA / None / PKCS1Padding”,因为它只能用于加密单个明文块(或者实际上是一个秘密密