RSA公鑰加密算法是1977年由羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一塊兒提出的。當時他們三人都在麻省理工學院工做。RSA就是他們三人姓氏開頭字母拼在一塊兒組成的。java
RSA是目前最有影響力的公鑰加密算法,它可以抵抗到目前爲止已知的絕大多數密碼攻擊,已被ISO推薦爲公鑰數據加密算法。算法
RSA算法是一種非對稱密碼算法,所謂非對稱,就是指該算法須要一對密鑰,使用其中一個加密,則須要用另外一個才能解密。安全
關於RSA算法的原理,這裏就再也不詳加介紹,網上各類資源一大堆。下面就開始介紹RSA加密解密JAVA類的具體實現。編碼
import java.security.MessageDigest; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; public class Coder { public static final String KEY_SHA="SHA"; public static final String KEY_MD5="MD5"; /** * BASE64解密 * @param key * @return * @throws Exception */ public static byte[] decryptBASE64(String key) throws Exception{ return (new BASE64Decoder()).decodeBuffer(key); } /** * BASE64加密 * @param key * @return * @throws Exception */ public static String encryptBASE64(byte[] key)throws Exception{ return (new BASE64Encoder()).encodeBuffer(key); } /** * MD5加密 * @param data * @return * @throws Exception */ public static byte[] encryptMD5(byte[] data)throws Exception{ MessageDigest md5 = MessageDigest.getInstance(KEY_MD5); md5.update(data); return md5.digest(); } /** * SHA加密 * @param data * @return * @throws Exception */ public static byte[] encryptSHA(byte[] data)throws Exception{ MessageDigest sha = MessageDigest.getInstance(KEY_SHA); sha.update(data); return sha.digest(); } }
先提供Coder編碼類,該類封裝了基本的Base6四、md5和SHA加密解密算法。Java對這些算法的實現提供了很好的API封裝,開發人員只需調用這些API就可很簡單方便的實現數據的加密與解密。加密
下面提供RSA加密解密類,該類爲Coder類子類,由於其中對RSA公私密鑰的保存進行了一層Base64加密處理。 spa
RSA加密解密類靜態常量 code
public static final String KEY_ALGORTHM="RSA";// public static final String SIGNATURE_ALGORITHM="MD5withRSA"; public static final String PUBLIC_KEY = "RSAPublicKey";//公鑰
public static final String PRIVATE_KEY = "RSAPrivateKey";//私鑰
RSA加密解密的實現,須要有一對公私密鑰,公私密鑰的初始化以下:對象
/** * 初始化密鑰 * @return * @throws Exception */ public static Map<String,Object> initKey()throws Exception{ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORTHM); keyPairGenerator.initialize(1024); KeyPair keyPair = keyPairGenerator.generateKeyPair(); //公鑰 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); //私鑰 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String,Object> keyMap = new HashMap<String, Object>(2); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; }
從代碼中能夠看出密鑰的初始化長度爲1024位,密鑰的長度越長,安全性就越好,可是加密解密所用的時間就會越多。而一次能加密的密文長度也與密鑰的長度成正比。一次能加密的密文長度爲:密鑰的長度/8-11。因此1024bit長度的密鑰一次能夠加密的密文爲1024/8-11=117bit。因此非對稱加密通常都用於加密對稱加密算法的密鑰,而不是直接加密內容。對於小文件能夠使用RSA加密,但加密過程仍可能會使用分段加密。blog
從map中獲取公鑰、私鑰 ip
/** * 取得公鑰,並轉化爲String類型 * @param keyMap * @return * @throws Exception */ public static String getPublicKey(Map<String, Object> keyMap)throws Exception{ Key key = (Key) keyMap.get(PUBLIC_KEY); return encryptBASE64(key.getEncoded()); } /** * 取得私鑰,並轉化爲String類型 * @param keyMap * @return * @throws Exception */ public static String getPrivateKey(Map<String, Object> keyMap) throws Exception{ Key key = (Key) keyMap.get(PRIVATE_KEY); return encryptBASE64(key.getEncoded()); }
對於RSA產生的公鑰、私鑰,咱們能夠有兩種方式能夠對信息進行加密解密。私鑰加密-公鑰解密 和 公鑰加密-私鑰解密。
私鑰加密
/** * 用私鑰加密 * @param data 加密數據 * @param key 密鑰 * @return * @throws Exception */ public static byte[] encryptByPrivateKey(byte[] data,String key)throws Exception{ //解密密鑰 byte[] keyBytes = decryptBASE64(key); //取私鑰 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM); Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); //對數據加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateKey); return cipher.doFinal(data); }
私鑰解密
/** * 用私鑰解密 * @param data 加密數據 * @param key 密鑰 * @return * @throws Exception */ public static byte[] decryptByPrivateKey(byte[] data,String key)throws Exception{ //對私鑰解密 byte[] keyBytes = decryptBASE64(key); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM); Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); //對數據解密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(data); }
公鑰加密
/** * 用公鑰加密 * @param data 加密數據 * @param key 密鑰 * @return * @throws Exception */ public static byte[] encryptByPublicKey(byte[] data,String key)throws Exception{ //對公鑰解密 byte[] keyBytes = decryptBASE64(key); //取公鑰 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM); Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec); //對數據解密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(data); }
公鑰解密
/** * 用公鑰解密 * @param data 加密數據 * @param key 密鑰 * @return * @throws Exception */ public static byte[] decryptByPublicKey(byte[] data,String key)throws Exception{ //對私鑰解密 byte[] keyBytes = decryptBASE64(key); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM); Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec); //對數據解密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicKey); return cipher.doFinal(data); }
關於數字簽名,先了解下何爲數字簽名。數字簽名,就是隻有信息的發送者才能產生的別人沒法僞造的一段數字串,這段數字串同時也是對信息的發送者發送信息真實性的一個有效證實。數字簽名是非對稱密鑰加密技術與數字摘要技術的應用。簡單地說,所謂數字簽名就是附加在數據單元上的一些數據,或是對數據單元所做的密碼變換。這種數據或變換容許數據單元的接收者用以確認數據單元的來源和數據單元的完整性並保護數據,防止被人(例如接收者)進行僞造。
數字簽名的主要功能以下:
保證信息傳輸的完整性、發送者的身份認證、防止交易中的抵賴發生。
數字簽名技術是將摘要信息用發送者的私鑰加密,與原文一塊兒傳送給接收者。接收者只有用發送者的公鑰才能解密被加密的摘要信息,而後用對收到的原文產生一個摘要信息,與解密的摘要信息對比。若是相同,則說明收到的信息是完整的,在傳輸過程當中沒有被修改,不然說明信息被修改過,所以數字簽名可以驗證信息的完整性。
數字簽名是個加密的過程,數字簽名驗證是個解密的過程。
數字簽名算法依靠公鑰加密技術來實現的。在公鑰加密技術裏,每個使用者有一對密鑰:一把公鑰和一把私鑰。公鑰能夠自由發佈,但私鑰則祕密保存;還有一個要求就是要讓經過公鑰推算出私鑰的作法不可能實現。
普通的數字簽名算法包括三種算法:
1.密碼生成算法;
2.標記算法;
3.驗證算法。
經過RSA加密解密算法,咱們能夠實現數字簽名的功能。咱們能夠用私鑰對信息生成數字簽名,再用公鑰來校驗數字簽名,固然也能夠反過來公鑰簽名,私鑰校驗。
私鑰簽名
/** * 用私鑰對信息生成數字簽名 * @param data //加密數據 * @param privateKey //私鑰 * @return * @throws Exception */ public static String sign(byte[] data,String privateKey)throws Exception{ //解密私鑰 byte[] keyBytes = decryptBASE64(privateKey); //構造PKCS8EncodedKeySpec對象 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes); //指定加密算法 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM); //取私鑰匙對象 PrivateKey privateKey2 = keyFactory.generatePrivate(pkcs8EncodedKeySpec); //用私鑰對信息生成數字簽名 Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(privateKey2); signature.update(data); return encryptBASE64(signature.sign()); }
公鑰校驗
/** * 校驗數字簽名 * @param data 加密數據 * @param publicKey 公鑰 * @param sign 數字簽名 * @return * @throws Exception */ public static boolean verify(byte[] data,String publicKey,String sign)throws Exception{ //解密公鑰 byte[] keyBytes = decryptBASE64(publicKey); //構造X509EncodedKeySpec對象 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); //指定加密算法 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM); //取公鑰匙對象 PublicKey publicKey2 = keyFactory.generatePublic(x509EncodedKeySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(publicKey2); signature.update(data); //驗證簽名是否正常 return signature.verify(decryptBASE64(sign)); }