Я пытаюсь получить эквивалент следующего метода С#:
public byte[] SignHash(byte[] btHash, string SN)
{
string strSignature = string.Empty;
X509Store x509store = null;
x509store = new X509Store(StoreLocation.CurrentUser);
x509store.Open(OpenFlags.ReadOnly);
foreach (X509Certificate2 x509 in x509store.Certificates)
{
if (x509.SerialNumber.ToLower().Contains(SN.ToLower()))
{
byte[] btSignature = null;
using (RSACryptoServiceProvider key = new RSACryptoServiceProvider())
{
key.FromXmlString(x509.PrivateKey.ToXmlString(true));
return key.SignHash(btHash, CryptoConfig.MapNameToOID("SHA256"));
}
break;
}
}
return null;
}
В языке Java. На самом деле, я пришел к следующему:
private static String SignHash(final byte[] btHash, String SerialNumber) throws Exception
{
KeyStore ks = null;
ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);
Boolean noValidCertificate = true;
Enumeration<String> en = ks.aliases();
ArrayList<String> lstAlias = Collections.list(en);
lstErreurs.add(lstAlias.size() + " certificate(s) found");
for (String aliasKey : lstAlias)
{
X509Certificate cert = (X509Certificate) ks.getCertificate(aliasKey);
Certificat = Base64Coder.encodeBase64String(cert.getEncoded());
Boolean blnCertificateFound = false;
if (SerialNumber != null && !SerialNumber.equals(""))
{
String SerialNumberCert = cert.getSerialNumber().toString(16);
if (SerialNumber.toLowerCase().contains(SerialNumberCert.toLowerCase())
|| SerialNumberCert.toLowerCase().contains(SerialNumber.toLowerCase()))
{
blnCertificateFound = true;
}
}
if (blnCertificateFound == false)
{
continue;
}
Provider p = ks.getProvider();
boolean isHashToSign = false;
for (String strToSign : input.split(";")) {
if(strToSign.length() == 44 && General.isBase64(strToSign)) {
isHashToSign = true;
break;
}
}
String algorithm = "";
if(isHashToSign)
{
algorithm = "RSA";
} else {
algorithm = "SHA256withRSA";
}
Signature sig = Signature.getInstance(algorithm, p);
PrivateKey key = (PrivateKey) ks.getKey(aliasKey, "1234".toCharArray());
if (key != null)
{
noValidCertificate = false;
sig.initSign(key);
String[] TabToSign = input.split(";");
String strResultSignature = "";
String separator = "";
for (String strToSign : TabToSign)
{
byte[] btToSign = null;
if(isHashToSign) {
btToSign = General.Base64_Decode_To_ByteArray(strToSign.getBytes(Charset.forName("UTF-8")));
} else {
btToSign = strToSign.getBytes(Charset.forName("UTF-8"));
}
sig.update(btToSign);
byte[] res = sig.sign();
String resB64 = Base64Coder.encodeBase64String(res);
strResultSignature += separator + resB64;
separator = ";";
}
return strResultSignature;
}
}
return null;
}
Но получение алгоритма "RSA" не работает для подписи. Я наконец подписываю Hash of Hash на Java. Я хотел бы подписать байт массива SHA256 без хеширования его снова. Как я могу прийти к этому результату? (для информации я использую хранилище сертификатов Windows, поэтому мне нужно работать с поставщиком Sun MSCAPI).
РЕДАКТИРОВАТЬ 1:
Я попытался использовать алгоритм "NONEwithRSA", но результат подписи отличается от подписи в .NET с помощью метода SignHash.
ИЗМЕНИТЬ 2:
Следующий поток: Разница между SHA256withRSA и SHA256, затем RSA объясняет, что на самом деле возможно подписать хэш, но для этого метода требуется BouncyCastle.
Я не могу работать с BouncyCastle, потому что мне нужно использовать провайдера Sun MSCAPI (хранилище сертификатов Windows). Я должен найти альтернативу BouncyCastle (если BC не позволяет нам использовать поставщика Sun MSCAPI).