數字簽名(又稱公鑰數字簽名)是一種類似寫在紙上的普通的物理簽名,但是使用了公鑰加密領域的技術實現,用於鑑別數字信息的方法。一套數字簽名通常定義兩種互補的運算,一個用於簽名,另一個用於驗證,但法條中的電子簽章與數字簽名,代表之意義並不相同,電子簽章用以辨識及確認電子文件簽署人身份、資格及電子文件真僞者。而數字簽名則是以數學算法或其他方式運算對其加密,才形成電子簽章,意即使用數字簽名才創造出電子簽章。 ——————— 摘自維基百科
簽名的好處
簽名可以保證數據完整性、不可抵賴性、鑑權
簽名過程
發送方A將需要傳送的數據通過自己的私鑰(Private Key)進行簽名產生摘要,然後將簽名生成的摘要和需要傳送的數據一起傳輸給接收方B,接收方B在接收到數據後通過A的公鑰(Public Key)來對簽名進行校驗。
RSA簽名算法
算法 | 密鑰長度 | 默認長度 | 簽名長度 | 實現方 |
MD2withRSA | 512~65536(64的整數倍) | 1024 | 與密鑰長度相同 | JDK |
MD5withRSA | ||||
SHA1withRSA | ||||
SHA224withRSA | 2048 | BC | ||
SHA256withRSA | ||||
SHA384withRSA | ||||
SHA512withRSA | ||||
RIPEMD128withRSA | ||||
RIPEMD168withRSA |
代碼實現:
public class SignatureWithRSA {
// 公/私鑰生成算法
private final static String KEY_ALGORITHM = "RSA";
// 數據簽名算法
/**
* JDK實現的RSA簽名算法有 MD2withRSA、MD5withRSA、SHA1withRSA
* 密鑰長度爲512~65536(要求爲64的整數倍),默認長度爲1024,簽名的長度和密鑰長度相等
*
* 其他的RSA簽名算法有SHA224withRSA、SHA256withRSA、SHA512withRSA等JDK並未實現,
* 但是bouncycastle都做了支持,默認密鑰爲2048,簽名長度同樣和密鑰長度相等
* */
private static final String SIGN_ALGORITHM = "SHA1withRSA";
private static final String PUBLIC_KEY = "publicKey";
private static final String PRIVATE_KEY = "privateKey";
private static final int KEY_LENGTH = 512;
/**
* 初始化密鑰
* @throws Exception
* */
public static Map<String, Key> initKey() throws Exception {
// 實例化密鑰生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
// 初始化密鑰長度,此處爲512
keyPairGenerator.initialize(KEY_LENGTH);
// 獲取密鑰對
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 獲取RSA公鑰
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
// 獲取RSA私鑰
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String, Key> keyMap = new HashMap<String, Key>();
keyMap.put(PUBLIC_KEY, rsaPublicKey);
keyMap.put(PRIVATE_KEY, rsaPrivateKey);
return keyMap;
}
/**
* 獲取公鑰
* */
public static RSAPublicKey getPublicKey(Map<String, Key> keyMap) {
return (RSAPublicKey) keyMap.get(PUBLIC_KEY);
}
/**
* 獲取私鑰
* */
public static RSAPrivateKey getPrivateKey(Map<String, Key> keyMap) {
return (RSAPrivateKey) keyMap.get(PRIVATE_KEY);
}
/**
* 使用私鑰對數據進行簽名
* @throws Exception
* @return byte[]
* */
public static byte[] signatureWithPrivateKey(String data, RSAPrivateKey rsaPrivateKey) throws Exception {
PKCS8EncodedKeySpec encodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 獲取私鑰
PrivateKey privateKey = keyFactory.generatePrivate(encodedKeySpec);
// 使用簽名算法實例化Signature
Signature signature = Signature.getInstance(SIGN_ALGORITHM);
// 使用簽名私鑰進行初始化
signature.initSign(privateKey);
// 更新需要簽名的數據
signature.update(data.getBytes());
// 執行簽名
byte[] signed = signature.sign();
return signed;
}
/**
* 使用公鑰對簽名的數據進行校驗
* @throws Exception
* */
public static boolean verifyWithPublicKey(String data, byte[] signed, RSAPublicKey rsaPublicKey) throws Exception {
X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
// 實例化KeyFactory
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 獲取簽名公鑰
PublicKey publicKey = keyFactory.generatePublic(encodedKeySpec);
Signature signature = Signature.getInstance(SIGN_ALGORITHM);
signature.initVerify(publicKey);
signature.update(data.getBytes());
boolean verified = signature.verify(signed);
return verified;
}
public static void main(String[] args) throws Exception {
String msg = "Hello World";
Map<String, Key> keyMap = initKey();
RSAPrivateKey priK = getPrivateKey(keyMap);
RSAPublicKey pubK = getPublicKey(keyMap);
System.out.println("簽名前的數據---->" + msg);
// 執行簽名
byte[] signedMsg = signatureWithPrivateKey(msg, priK);
System.out.println("密鑰長度---->" + KEY_LENGTH);
System.out.println("簽名後數據長度---->" + signedMsg.length * 8);
System.out.println("簽名後的數據---->" + Base64.encodeBase64String(signedMsg));
// 校驗簽名
boolean verified = verifyWithPublicKey(msg, signedMsg, pubK);
System.out.println("校驗---->" + verified);
}
}
輸出的結果:
以上,就是對RSA簽名算法的簡單介紹,如有錯誤請指出,謝謝!