本文介紹了Java/Android數字簽名(RSA密鑰)的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
我想用存儲在數據庫中的私鑰(RSA)在我的Java/Android項目中生成數字簽名。
我的2個密鑰是用以下代碼生成的(項目正在生產中,我無法更改它):
// 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));
}
基于不同的站點(here和here),我將嘗試編寫生成簽名的代碼:
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”。
我是加密界的新手,請原諒我的骯臟代碼。
-編輯
調用Verify方法時出現異常:
java.security.SignatureException:簽名編碼錯誤
推薦答案
簽名時,您返回了使用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/Android數字簽名(RSA密鑰)的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,