摇曳的蔷薇
控制器部分生成 RSA 密钥(公共和私有)package com.secure.encryption.decryption.controller;import java.io.UnsupportedEncodingException;import java.nio.charset.StandardCharsets;import java.util.Base64;import java.util.Date;import java.util.HashMap;import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.CrossOrigin;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RestController;import com.secure.encryption.decryption.rsa.keystore.KeyStore;import com.secure.encryption.decryption.rsa.service.RSAKeyPairGenerator;import com.secure.encryption.decryption.util.AesUtil;@RestControllerpublic class EncryptDecryptController { @Autowired RSAKeyPairGenerator rsa; @Autowired KeyStore keystore; @CrossOrigin @GetMapping(value = "get/rsa/public") public Map<String, Object> generateRSA_PUBLIC_PRIVATE_KEY() { Map<String, Object> response = new HashMap<>(); /** * Below function creates rsa public & private key * While this api only share PUBLICKEY * Whereas PRIVATEKEY is stored in bean/model */ String public_KEY = null; public_KEY = rsa.KeyPairGenerator(); response.put("public", public_KEY); return response; } @CrossOrigin @PostMapping(value = "/decrypt/AES_encyptedKEY/with/RSA_privateKEY/decryptdata/with/aes") public Map<String, Object> decrypt(@RequestBody Map<String, Object> req) throws UnsupportedEncodingException { /** * First decrypt AES-Key which is encrypted with RSA Public Key * Use RSA privateKey for decryption */ String Decrypted_AES_Key = rsa.decrypt(req.get("phrase").toString(),keystore.getPrivateKey()); byte[] decoded = Base64.getDecoder().decode(req.get("data").toString()); String encryptedAES_Data = new String(decoded, StandardCharsets.UTF_8); /** * Decode data to base 64 * Use AES key to decrypt the data */ AesUtil aesUtil = new AesUtil(128, 1000); String decryptedAES_Data = aesUtil.decrypt( req.get("salt").toString(), req.get("iv").toString(), Decrypted_AES_Key, encryptedAES_Data); /** * Map actual data as response */ req.put("data", decryptedAES_Data); return req; } @CrossOrigin @GetMapping(value = "/decryptfrom/backend/aes/plain/decrypt/frontend") public Map<String, Object> sendAESencryptedData() { /** * Generate random key * Encrypt data using same * pass key to UI * Decrypt using same key, iv and salt */ Map<String, Object> response = new HashMap<>(); int i = (int) (new Date().getTime()/1000); //String iv = generateIv().toString(); AesUtil aesUtil = new AesUtil(128, 1000); String phrase = String.valueOf(i);//"my secret key 123"; //String salt = new String(generateSalt(32)); String iv = "bb6a69ace7a11a38fba164238e000c7c"; String salt = "6c3674b6469467ab0b9f2b57ce36e78d"; String encryptedAES_Data = Base64.getEncoder().encodeToString( aesUtil.encrypt( salt, iv, phrase, "ganesha") ); response.put("data", encryptedAES_Data); response.put("salt", salt); response.put("iv", iv); response.put("key", phrase); return response; } /* public IvParameterSpec generateIv() { byte[] iv = new byte[16]; new SecureRandom().nextBytes(iv); return new IvParameterSpec(iv); } private byte[] generateSalt(int size) { try { byte[] salt = new byte[size]; SecureRandom rand = SecureRandom.getInstance("SHA1PRNG"); rand.nextBytes(salt); return salt; } catch (Exception e) { System.err.println(e); } return null; } */ }生成 RSA 随机密钥的服务package com.secure.encryption.decryption.rsa.service;public interface RSAKeyPairGenerator { public String KeyPairGenerator(); public byte[] encrypt(String data, String publicKey); public String decrypt(String data, String base64PrivateKey);}实现类package com.secure.encryption.decryption.rsa.service;import java.security.InvalidKeyException;import java.security.KeyFactory;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.NoSuchAlgorithmException;import java.security.PrivateKey;import java.security.PublicKey;import java.security.spec.InvalidKeySpecException;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;import java.util.Base64;import java.util.HashMap;import java.util.Map;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.NoSuchPaddingException;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.secure.encryption.decryption.rsa.keystore.KeyStore;@Servicepublic class RSAKeyPairGeneratorImpl implements RSAKeyPairGenerator{ @Autowired KeyStore keystore; @Override public String KeyPairGenerator() { Map<String, Object> keypair = new HashMap<String, Object>(); try { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); keyGen.initialize(1024); KeyPair pair = keyGen.generateKeyPair(); final String privatestring = Base64.getEncoder().encodeToString(pair.getPrivate().getEncoded()); final String publicstring = Base64.getEncoder().encodeToString(pair.getPublic().getEncoded()); keystore.setPrivateKey(privatestring); return publicstring; } catch (Exception e) { System.err.println(e); } return null; } private static PublicKey getPublicKey(String base64PublicKey){ PublicKey publicKey = null; try{ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(base64PublicKey.getBytes())); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); publicKey = keyFactory.generatePublic(keySpec); return publicKey; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeySpecException e) { e.printStackTrace(); } return publicKey; } private static PrivateKey getPrivateKey(String base64PrivateKey){ PrivateKey privateKey = null; PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(base64PrivateKey.getBytes())); KeyFactory keyFactory = null; try { keyFactory = KeyFactory.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } try { privateKey = keyFactory.generatePrivate(keySpec); } catch (InvalidKeySpecException e) { e.printStackTrace(); } return privateKey; } public byte[] encrypt(String data, String publicKey) {//throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException { try { //AES/CBC/PKCS5Padding //RSA/ECB/PKCS1Padding Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKey)); return cipher.doFinal(data.getBytes()); } catch (Exception e) { System.err.println(e); } return null; } private static String decrypt(byte[] data, PrivateKey privateKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, privateKey); return new String(cipher.doFinal(data)); } public String decrypt(String data, String base64PrivateKey) {//throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException { try { return decrypt(Base64.getDecoder().decode(data.getBytes()), getPrivateKey(base64PrivateKey)); } catch (InvalidKeyException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchPaddingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (BadPaddingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalBlockSizeException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; }}AesUtil 类package com.secure.encryption.decryption.util;import java.io.UnsupportedEncodingException;import java.security.InvalidAlgorithmParameterException;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.security.spec.InvalidKeySpecException;import java.security.spec.KeySpec;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.NoSuchPaddingException;import javax.crypto.SecretKey;import javax.crypto.SecretKeyFactory;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.PBEKeySpec;import javax.crypto.spec.SecretKeySpec;import org.apache.commons.codec.DecoderException;import org.apache.commons.codec.binary.Hex;import org.apache.tomcat.util.codec.binary.Base64;public class AesUtil { private final int keySize; private final int iterationCount; private final Cipher cipher; public AesUtil(int keySize, int iterationCount) { this.keySize = keySize; this.iterationCount = iterationCount; try { cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { throw fail(e); } } public byte[] encrypt(String salt, String iv, String passphrase, String plaintext) { try { SecretKey key = generateKey(salt, passphrase); byte[] encrypted = doFinal(Cipher.ENCRYPT_MODE, key, iv, plaintext.getBytes("UTF-8")); System.out.println(encrypted); return encrypted;//Base64.getEncoder().encodeToString(encrypted); //String s = Base64.getEncoder().encodeToString(encrypted); } catch (UnsupportedEncodingException e) { throw fail(e); } } public String decrypt(String salt, String iv, String passphrase, String ciphertext) { try { SecretKey key = generateKey(salt, passphrase); byte[] decrypted = doFinal(Cipher.DECRYPT_MODE, key, iv, base64(ciphertext)); return new String(decrypted, "UTF-8"); } catch (UnsupportedEncodingException e) { return null; }catch (Exception e){ return null; } } private byte[] doFinal(int encryptMode, SecretKey key, String iv, byte[] bytes) { try { cipher.init(encryptMode, key, new IvParameterSpec(hex(iv))); return cipher.doFinal(bytes); } catch (InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { return null; } } private SecretKey generateKey(String salt, String passphrase) { try { SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), hex(salt), iterationCount, keySize); SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES"); return key; } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { return null; } } public static byte[] base64(String str) { return Base64.decodeBase64(str); } public static byte[] hex(String str) { try { return Hex.decodeHex(str.toCharArray()); } catch (DecoderException e) { throw new IllegalStateException(e); } } private IllegalStateException fail(Exception e) { return null; }}遵循的步骤使用 RSA 密钥生成随机 AES(密钥、iv、盐)- 使用 crypto.js使用 AES 并加密易受攻击的数据使用RSA公钥加密AES密钥通过网络发送加密数据和密钥服务使用 AES 数据解密密钥使用AES密钥解密数据将数据发送回前端Html页面供参考<!DOCTYPE html><html><body> <script src="jquery.min.js"></script> <script src="jsencrypt.min.js"></script><script type="text/javascript" src="crypto-js.min.js"></script><script type="text/javascript" src="aes.js"></script><script type="text/javascript">const payloadsample = { "addressLine1": "301,Kamala Mills Compound", "addressLine2": "Gr Flr, Tulsi Pipe Rd, Lower Parel ", "addressLine4": "Mumbai, Maharashtra", "zipcode": 400071};/**Step 1 ) - get data**//**Step 2 ) - get RSA pub Key**/function hybridEncryption(){ $.ajax({ type: 'GET',//post url: 'http://localhost:1818/get/rsa/public', success: function(res) { let RSAEncrypt = new JSEncrypt(); RSAEncrypt.setPublicKey(res.public);//set RSA public key const key = Math.random().toString(36).slice(2);//Generate random AES key console.log("key ", key); var iv = CryptoJS.lib.WordArray.random(128/8).toString(CryptoJS.enc.Hex); var salt = CryptoJS.lib.WordArray.random(128/8).toString(CryptoJS.enc.Hex); var aesUtil = new AesUtil(128, 1000); debugger console.log(key) var data = JSON.stringify({ payloadsample }); var ciphertext = aesUtil.encrypt(salt, iv, key, data);/**Step 3 ) - generate key **/ senData(RSAEncrypt, iv, salt, key, btoa(ciphertext)) }, error:function(e) { console.error(e); }, contentType: "application/json", dataType: 'json' }); }function senData(RSAEncrypt, iv, salt, key, base64Content){ const payload = { "phrase":RSAEncrypt.encrypt(key),//encrypt with RSA "data":base64Content, "iv":iv, "salt":salt } console.log("sending : ", payload); $.ajax({ type: 'POST', url: 'http://localhost:1818/decrypt/AES_encyptedKEY/with/RSA_privateKEY/decryptdata/with/aes', data: JSON.stringify (payload), // or JSON.stringify ({name: 'jonas'}), success: function(data) { console.log(data); }, error:function(e) { console.error(e); }, contentType: "application/json", dataType: 'json' });} hybridEncryption();/** * Incase of Backend encryption to Front end Decryption * decryptBE() - will get AES encrypted data with associated data * */function decryptBE(){ $.ajax({ type: 'GET',//post url: 'http://localhost:1818/decryptfrom/backend/aes/plain/decrypt/frontend', success: function(res) { debugger var aesUtil = new AesUtil(128, 1000); var ciphertext = aesUtil.decrypt(res.salt, res.iv, res.key, res.data); console.log(ciphertext); }, error:function(e) { console.error(e); }, contentType: "application/json", dataType: 'json' });}</script></body></html> 这是一个使用参考的工作示例使用的其他库是 aes.jsvar AesUtil = function(keySize, iterationCount) { this.keySize = keySize / 32; this.iterationCount = iterationCount;};AesUtil.prototype.generateKey = function(salt, passPhrase) { var key = CryptoJS.PBKDF2( passPhrase, CryptoJS.enc.Hex.parse(salt), { keySize: this.keySize, iterations: this.iterationCount }); return key;}AesUtil.prototype.encrypt = function(salt, iv, passPhrase, plainText) { var key = this.generateKey(salt, passPhrase); var encrypted = CryptoJS.AES.encrypt( plainText, key, { iv: CryptoJS.enc.Hex.parse(iv) }); return encrypted.ciphertext.toString(CryptoJS.enc.Base64);}AesUtil.prototype.decrypt = function(salt, iv, passPhrase, cipherText) { var key = this.generateKey(salt, passPhrase); var cipherParams = CryptoJS.lib.CipherParams.create({ ciphertext: CryptoJS.enc.Base64.parse(cipherText) }); var decrypted = CryptoJS.AES.decrypt( cipherParams, key, { iv: CryptoJS.enc.Hex.parse(iv) }); return decrypted.toString(CryptoJS.enc.Utf8);}其余的是JSEncrypt v2.3.1 https://npmcdn.com/jsencrypt@2.3.1/LICENSE.txt最后是 crypto-js.min.js谢谢,我希望这会有用