RSA算法是第一個能同時用於加密和數字簽名的算法,也易於理解和操做。RSA是被研究得最普遍的公鑰算法,從提出到現今的三十多年裏,經歷了各類攻擊的考驗,逐漸爲人們接受,廣泛認爲是目前最優秀的公鑰方案之一。RSA公開密鑰密碼體制。所謂的公開密鑰密碼體制就是使用不一樣的加密密鑰與解密密鑰,是一種「由已知加密密鑰推導出解密密鑰在計算上是不可行的」密碼體制。java
RSA的算法涉及三個參數,n、e一、e2。其中,n是兩個大質數p、q的積,n的二進制表示時所佔用的位數,就是所謂的密鑰長度。e1和e2是一對相關的值,e1能夠任意取。git
爲了產生兩個密鑰,選取兩個大素數,p和q,爲了得到最大程度的安全性,兩數的長度同樣。計算乘積算法
n=p*q;
安全
隨機取加密密鑰e,使得e 和(p-1)(q-1) 互素,最後採用擴展歐幾里得算法計算解密密鑰d,編碼
d=e^-1 mod (p-1)(q-1)
d和n也是互素。e和n是公開密鑰,d是私人密鑰。加密
RSA加解密的算法徹底相同,設A爲明文,B爲密文,則:設計
A=B^d mod n;3d
B=A^e mod n;code
公鑰加密體制中,通常用公鑰加密,私鑰解密orm
e1和e2能夠互換使用,即:
A=B^e mod n;
B=A^d mod n;
咱們能夠設計出一對公私密鑰,加密密鑰(公鑰)爲:KU =(e,n)=(3,33),解密密鑰(私鑰)爲:KR =(d,n)=(7,33)。
將明文信息數字化,並將每塊兩個數字分組。假定明文英文字母編碼表爲按字母順序排列數值,即:
加密消息m時,首先將它分爲比n小的數據分組(採用二級制數,選取小於n的2的最大次冪),也就是說,若果p和n爲100位的素數,那麼n將有200位,每一個消息分組m應該小於200位長
用戶加密密鑰(3,33) 將數字化明文分組信息加密成密文。由C≡M^e(mod n)
得:
用戶B收到密文,若將其解密,只須要計算 M≡c^d(mod n)
用戶B獲得明文信息爲:11,05,25。根據上面的編碼表將其轉換爲英文,咱們又獲得了恢復後的原文「key」
最經常使用的三個e值:3, 17, 65537(2^16+1).
X.509中建議採用65537^[304], PEM中建議採用3^[37],PKCS#1建議採用3或65537^[1345].
RSA在應用中通常採用PKCS#1的標準進行填充
/** * RSA algorithm. */ public static final String KEY_ALGORITHM = "RSA"; /** * digital signature algorithm */ public static final String SIGNATURE_ALGORITHM = "SHA256withRSA"; /** * Gets public key. */ private static final String PUBLIC_KEY = "RSAPublicKey"; /** * Gets private key. */ private static final String PRIVATE_KEY = "RSAPrivateKey"; /** * RSA maximum encryption text size. */ private static final int MAX_ENCRYPT_BLOCK = 117; /** * RSA maximum decryption text size. */ private static final int MAX_DECRYPT_BLOCK = 128; /** * <p> * Use the private key to generate digital signatures for the information. * </p> * * @param data * Encrypted data * @param PrivateKey * Private Key (BASE64 encoding) * @return Digit signature (BASE64 encoding) * @throws Exception */ public byte[] sign(byte[] data, String privateKey) { try { byte[] keyBytes = Base64Utils.decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory; keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(privateK); signature.update(data); return signature.sign(); } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException e) { e.printStackTrace(); } return null; } /** * <p> * Verify digit signature. * </p> * * @param data * Encrypted data * @param publicKey * Public Key(BASE64 encoding) * @param sign * Digit signature * * @return result from verify * @throws Exception * */ public boolean verify(byte[] data, String publicKey, byte[] sign) { byte[] keyBytes = Base64Utils.decode(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory; try { keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PublicKey publicK = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(publicK); signature.update(data); return signature.verify(sign); } catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException | SignatureException e) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } /** * <P> * Decrypted with the private key * </p> * * @param encryptedData * Encrypted data * @param privateKey * Private Key (BASE64 encoding) * @return decryptedData * @throws Exception */ public byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) { byte[] keyBytes = Base64Utils.decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory; try { keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateK); ByteArrayOutputStream out = new ByteArrayOutputStream(); int inputLen = encryptedData.length; int offSet = 0; byte[] cache; int i = 0; // 對數據分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); return decryptedData; } catch (Exception e) { e.printStackTrace(); } return null; } /** * <p> * Encrypt with the public key. * </p> * * @param data * Plain text * @param publicKey * Public key(BASE64 encoding) * @return encryptedData * @throws Exception */ public byte[] encryptByPublicKey(byte[] data, String publicKey) { byte[] keyBytes = Base64Utils.decode(publicKey); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory; try { keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicK = keyFactory.generatePublic(x509KeySpec); // 對數據加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicK); ByteArrayOutputStream out = new ByteArrayOutputStream(); int inputLen = data.length; int offSet = 0; byte[] cache; int i = 0; // 對數據分段加密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_ENCRYPT_BLOCK; } byte[] encryptedData = out.toByteArray(); out.close(); return encryptedData; } catch (NoSuchAlgorithmException | InvalidKeySpecException | IOException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException | NoSuchPaddingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; }