[英]Add padding RSA PKCS#1 after hash SHA256 and before calling API of signature
为了使用存储在远程 HSM 中的证书(使用云签名),我实际上正在尝试使用 API 生成 PKCS#1.5 签名给定 SHA256 Hash。问题是我需要的协议规范实现填充过程必须在 PKCS#1 中的状态。
API支持的加密算法是这个OID:RSAES-PKCS1-v1_5加密方案
http://oid-info.com/get/1.2.840.113549.1.1.1
这是协议的规范,规定填充过程必须是 PKCS#1:
API 的开发人员提到,如果我能够填充在将 hash 发送到 API 之前生成的 hash 值,我将能够生成正确的签名。
下面是过程的解释:
但是我找不到任何方法来填充 hash 在生成之后和发送到 API 之前。
...
string pathFileToBeHashed = "D:\\Temp\\virsct.SCT";
// Gets content of file
// Removes invalid characters before hash
string strToHash = File.ReadAllText(pathFileToBeHashed);
strToHash = strToHash.Replace(Constants.vbCr, "");
strToHash = strToHash.Replace(Constants.vbLf, "");
strToHash = strToHash.Replace(Strings.ChrW(26).ToString(), "");
// Hash SHA256
byte[] btToHash = Encoding.UTF8.GetBytes(strToHash);
string strHashed = string.Empty;
using var sha256 = new SHA256Managed()
{
strHashed = Convert.ToBase64String(sha256.ComputeHash(btToHash));
}
// Send to the API
...
当我在hash被签名后使用下面的代码亲自检查签名时,结果是OK的。 我用来检查签名的方法如上所述。
private static bool IsSignatureOK(string certB64, string signB64, string strCheminCompletFichier)
{
X509Certificate2 x509 = null;
try
{
x509 = new X509Certificate2(Convert.FromBase64String(certB64));
using RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)x509.PublicKey.Key;
byte[] btSign = Convert.FromBase64String(signB64);
byte[] btFichier = File.ReadAllBytes(strCheminCompletFichier);
byte[] btHashFichier = null;
using (MemoryStream ms = new MemoryStream(btFichier))
{
btHashFichier = CalculateHash(ms);
}
return rsa.VerifyHash(btHashFichier, CryptoConfig.MapNameToOID("SHA256"), btSign);
}
catch (Exception ex)
{
Interaction.MsgBox($"KO : {ex.Message}");
return false;
}
finally
{
if (x509 != null)
x509.Reset();
}
}
public static byte[] CalculateHash(MemoryStream memStream)
{
byte[] btHashWithContext = null;
int BLOC_LENGTH = 1000000;
memStream.Position = 0;
int Nb_Blocs = Convert.ToInt32(memStream.Length / BLOC_LENGTH) + (memStream.Length % BLOC_LENGTH == 0 ? 0 : 1);
using (SHA256Managed hashAlgorithm = new SHA256Managed())
{
byte[] MyBuffer = null;
for (int j = 0; j <= Nb_Blocs - 1; j++)
{
MyBuffer = new byte[BLOC_LENGTH];
int Nb_octets_lus = memStream.Read(MyBuffer, 0, BLOC_LENGTH);
if (Nb_octets_lus != BLOC_LENGTH)
Array.Resize(ref MyBuffer, Nb_octets_lus);
string restemp = Encoding.UTF8.GetString(MyBuffer);
restemp = restemp.Replace(Constants.vbCr, "");
restemp = restemp.Replace(Constants.vbLf, "");
restemp = restemp.Replace(Strings.ChrW(26).ToString(), "");
byte[] MyTempArray = Encoding.UTF8.GetBytes(restemp);
hashAlgorithm.TransformBlock(MyTempArray, 0, MyTempArray.Length, null, 0);
MyTempArray = null;
}
hashAlgorithm.TransformFinalBlock(new byte[0], 0, 0);
btHashWithContext = hashAlgorithm.Hash;
}
return btHashWithContext;
}
是否有一种方法允许在生成后向 hash 添加填充?
根据这个网站:
https://www.ibm.com/docs/en/linux-on-systems?topic=cryptography-pkcs-1-hash-formats
如果在 hash 值的开头增加一些额外的字节,则可以根据 PKCS#1 签名获得结果
SHA256 Hash 的十六进制字节如下:
SHA-256
X'3031300D 06096086 48016503 04020105 000420'
在 C# 中,我只是这样添加了这些十六进制字节:
public void Main()
{
string hash = "3Z6TXNaRtoPP5kv5l4XBarx4GM+uH1M9rRK9iwRkKfY=";
byte[] btHash = Convert.FromBase64String(hash);
// Generates padding bytes to add at beginning of hash
string hexString = "3031300D060960864801650304020105000420";
byte[] btPadBytes = HexStringToByteArray(hexString);
// Combines both byte arrays
byte[] btCombined = ByteArrayCombine(bt, btHash);
string hashWithPadding = Convert.ToBase64String(btCombined);
}
public static byte[] HexStringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
public static byte[] ByteArrayCombine(byte[] first, byte[] second)
{
byte[] ret = new byte[first.Length + second.Length];
Buffer.BlockCopy(first, 0, ret, 0, first.Length);
Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
return ret;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.