java - java/android 中的数字签名(RSA key )

标签 java android encryption rsa digital-signature

我想在我的 java/android 项目中使用存储在数据库中的私钥 (RSA) 生成数字签名。

我的 2 个 key 是使用以下代码生成的(项目正在生产中,我无法更改它):

// Get keys pair (RSA)
KeyPair rsaKyePair = createKeyPair();

// Get private/ public keys and store them in DB
String pri = getPrivateKeyBase64Str(rsaKyePair);
String pub = getPublicKeyBase64Str(rsaKyePair));


public static KeyPair createKeyPair() {
    KeyPair keyPair = null;

    try {
        KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
        keygen.initialize(KEY_LENGTH);
        keyPair = keygen.generateKeyPair();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return null;
    }
    return keyPair;
}

public static String getPrivateKeyBase64Str(KeyPair keyPair){
    if (keyPair == null) return null;
    return getBase64StrFromByte(keyPair.getPrivate().getEncoded());
}

public static String getPublicKeyBase64Str(KeyPair keyPair){
    if (keyPair == null) return null;
    return getBase64StrFromByte(keyPair.getPublic().getEncoded());
}

public static String getBase64StrFromByte(byte[] key){
    if (key == null || key.length == 0) return null;
    return new String(Base64.encode(key));
}

基于不同的站点(herehere),我将尝试编写生成签名的代码:

String mySignature = getDigitalSignature("my_string_", "my_private_string" );

/*
 * Generated a signed String
 * @param text : string to sign
 * @param strPrivateKey : private key (String format)
 */
public String getDigitalSignature(String text, String strPrivateKey)  {

    try {

        // Get private key from String
        PrivateKey pk = loadPrivateKey(strPrivateKey);

        // text to bytes
        byte[] data = text.getBytes("UTF8");

        // signature
        Signature sig = Signature.getInstance("MD5WithRSA");
        sig.initSign(pk);
        sig.update(data);
        byte[] signatureBytes = sig.sign();

        return javax.xml.bind.DatatypeConverter.printBase64Binary(signatureBytes);

    }catch(Exception e){
        return null;
    }

}



private PrivateKey loadPrivateKey(String key64) throws GeneralSecurityException {
    byte[] clear = Base64.decode(key64, Base64.DEFAULT);
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(clear);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PrivateKey priv = fact.generatePrivate(keySpec);
    Arrays.fill(clear, (byte) 0);
    return priv;
}

为了验证签名,我在我的 java API 中使用了这段代码:

/*
 * Verify signature of a string
 * @param signature : signature
 * @param origina: original string to verify
 * @param publicKey: user public key 
 */
public static boolean verfiySignature(String signature, String original, String publicKey){

    try{

        // Get private key from String
        PublicKey pk = loadPublicKey(publicKey);

        // text to bytes
        byte[] originalBytes = original.getBytes("UTF8");

        //signature to bytes
        //byte[] signatureBytes = signature.getBytes("UTF8");
        byte[] signatureBytes =javax.xml.bind.DatatypeConverter.parseBase64Binary(signature);

        Signature sig = Signature.getInstance("MD5WithRSA");
        sig.initVerify(pk);
        sig.update(originalBytes);

        return sig.verify(signatureBytes);

    }catch(Exception e){
        e.printStackTrace();
        Logger log = Logger.getLogger(RsaCipher.class);
        log.error("error for signature:" + e.getMessage());
        return false;
    }

}


/*
 * Generate a PublicKey object from a string
 * @ key64 : public key in string format (BASE 64)
 */
private static PublicKey loadPublicKey(String key64) throws GeneralSecurityException {
    byte[] data = javax.xml.bind.DatatypeConverter.parseBase64Binary(key64);
    X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    return fact.generatePublic(spec);
}

我用真实数据运行了这段代码,但“verifySignature”总是返回“False”。

我是加密界的新手,请原谅我的脏代码。

--- 编辑

调用验证方法时出现异常:

java.security.SignatureException: Signature encoding error

最佳答案

签名时您返回了 base64 编码的签名:

return Base64.encodeToString(signatureBytes, Base64.DEFAULT);

因此,在验证时,您必须对签名字符串进行 base64 解码。但你要做的是:

byte[] signatureBytes = signature.getBytes("UTF8");

因此,您尝试验证的 signatureBytes 与您作为签名结果获得的 signatureBytes 完全不同。


您签名使用

Signature sig = Signature.getInstance("RSA");

但是你验证使用

Signature sig = Signature.getInstance("MD5WithRSA");

显然,您应该在两种情况下使用相同的算法。

关于java - java/android 中的数字签名(RSA key ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30929103/

相关文章:

ios - RNCryptor:使用 rncrypt (cli) 加密,然后在 iOS 中使用 RNDecryptor 解密

c++ - 奇怪的错误 char 的加密 (ascii)

java - 尝试将 JSON 数据发布到 Spring Controller ..根本不起作用

java - Tapestry - 事件的执行方法

java - Struts 2 中的 validate() 方法如何获得结果 "input"?

javascript - 我不能在 Android 上使用嵌入式 <style> CSS 吗?

android - API 21 状态栏后面的工具栏

java - 使用 JPA 查询可为空的 @OneToOne 关系

android - 如何在android中的日期中添加天数

java - TEA算法java实现和32位无符号位问题