Java中与.NET RSACryptoServiceProvider和SHA-1等效的功能是什么?

10

我有以下的C#数据签名代码:

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

string PrivateKeyText = "<RSAKeyValue><Modulus>....</D></RSAKeyValue>";

rsa.FromXmlString(PrivateKeyText);

string data = "my data";        

byte[] SignedByteData = rsa.SignData(Encoding.UTF8.GetBytes(data), new SHA1CryptoServiceProvider());

我希望您能够将以下代码转换为Java (Android):

String modulusElem = "...";
String expElem = "...";

byte[] expBytes = Base64.decode(expElem, Base64.DEFAULT);
byte[] modulusBytes = Base64.decode(modulusElem, Base64.DEFAULT);

BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger exponent = new BigInteger(1, expBytes);

try {
    KeyFactory factory = KeyFactory.getInstance("RSA");

    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");

    String data = "my data";

    MessageDigest md = MessageDigest.getInstance("SHA-1");
    byte[] hashedData = md.digest(data.getBytes("UTF-8"));

    RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(modulus, exponent);

    PublicKey publicKey = factory.generatePublic(pubSpec);

    cipher.init(Cipher.ENCRYPT_MODE, publicKey);

    byte[] SignedByteData = cipher.doFinal(hashedData);

} catch (Exception e){

}

但是我得到了不匹配的输出字节数组。我错在哪里?在 Cipher.getInstance(...) 中该使用什么转换?


请查看此链接:https://dev59.com/c2Ml5IYBdhLWcg3w1p26 - Zohra Khan
@ZohraKhan,我最初就是根据那篇帖子编写了我的Java代码。该帖子中使用的方法是“Encrypt”,而我正在使用具有内置哈希函数的“SignData”。 - Mohsen Afshin
1个回答

8

使用Signature.getInstance("SHA1withRSA")。加密和签名生成不同,有不同的填充机制。


Afshin更新

完整的解决方案。请注意使用私有指数,即<D>,而不是公共的<Exponent>

String modulusElem = "...";
String dElem = "...";

byte[] modulusBytes = Base64.decode(modulusElem, Base64.DEFAULT);
byte[] dBytes = Base64.decode(dElem, Base64.DEFAULT);

BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger d = new BigInteger(1, dBytes);

String data = "my data";            

try {
        Signature signature = Signature.getInstance("SHA1withRSA");

        KeyFactory factory = KeyFactory.getInstance("RSA");

        RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(modulus, d);

        PrivateKey privateKey = factory.generatePrivate(privateKeySpec);

        signature.initSign(privateKey);

        signature.update(data.getBytes("UTF-8"));

        byte[] SignedByteData = signature.sign();

} catch(Exception e) {
    e.printStackTrace();
}

PS: 这里我假设使用旧版的PKCS#1填充方式,RSACryptoServiceProvider文档中忘了提到所使用的填充机制。我的一个旧回答也做出了这个假设,看起来是正确的。 - Maarten Bodewes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接