Springboot interface encryption example (2)

RESTUDY A wolf on the road 2023-10-20 17:55 Published in Beijing

Included in the collection #Interface Encryption 2

The previous article introduced interface encryption and provided the corresponding project source code (please message me privately if necessary). It uses RSA encryption and decryption. Although it is highly secure, the encryption and decryption speed is slow. You can consider combining it with AES encryption and decryption.

RSA

  • Features: Only need to exchange public keys; public/private key mechanism, public key encryption, private key decryption (or private key encryption, public key decryption); the public key is responsible for encryption, the private key is responsible for decryption; the private key is responsible for signing, and the public key is responsible verify

  • Disadvantages: Encryption and decryption are slow, especially decryption

AES

  • Features: Use the same secret key for encryption and decryption

  • Advantages: fast, efficient

  • Disadvantages: The secret key is not secure

In actual projects, consider the combination of RSA + AES:

  • Generate a random AES key string

  • Use the RSA public key to encrypt the AES key, and then use the AES key to encrypt the real content

  • Pass the skey=encrypted AES key and body=the content encrypted by the AES key.

  • The other party uses the RSA private key to decrypt the AES key skey, and then uses the AES key to decrypt the content.

Code Example

Only encrypted util is provided. If you need the source code, leave me a message.

public class AESUtil {<!-- --></code><code> private static SecureRandom random = new SecureRandom();</code><code> private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding ";</code><code> </code><code> /**</code><code> * Get a random 16-digit key, the key must be an integer multiple of 10</code><code> * @return </code><code> */</code><code> public static String getAesKey() {<!-- --></code><code> final Integer keyLenth = 16;</code><code> StringBuilder ret = new StringBuilder();</code><code> for (int i = 0; i < keyLenth; i + + ) {<!-- --></code><code> // Output letters or Number</code><code> boolean isChar = (random.nextInt(2) % 2 == 0);</code><code> // String</code><code> if (isChar) {<! -- --></code><code> // Get uppercase letters or lowercase letters</code><code> int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;</code> <code> ret.append((char) (choice + random.nextInt(26)));</code><code> } else { // Number</code><code> ret.append(random.nextInt( 10));</code><code> }</code><code> }</code><code> return ret.toString();</code><code> }</code><code> / **</code><code> * Encryption method, using key as vector iv to increase the strength of the encryption algorithm</code><code> * More secure</code><code> * @param key key</code><code> * @param raw content that needs to be encrypted</code><code> * @return</code><code> */</code><code> public static byte[] encrypt(byte[] key, String raw) throws Exception {<!-- --></code><code> // First encryption</code><code> SecretKeySpec secretKey = new SecretKeySpec(key, "AES");</code> <code> byte[] enCodeFormat = secretKey.getEncoded();</code><code> // Get the secondary encryption key</code><code> SecretKeySpec secondSecretKey = new SecretKeySpec(enCodeFormat, "AES");</code><code> Cipher cipher = Cipher.getInstance(AES_ALGORITHM);</code><code> // Vector iv, increases the strength of the encryption algorithm</code><code> IvParameterSpec iv = new IvParameterSpec(key);</code><code> // Initialize the cipher</code><code> cipher.init(Cipher.ENCRYPT_MODE, secondSecretKey, iv);</code><code> // Encryption</code><code> byte[ ] result = cipher.doFinal(raw.getBytes());</code><code> return result;</code><code> }</code><code> /**</code><code> * Decryption method, using key as vector iv to increase the strength of the encryption algorithm</code><code> * @param key key</code><code> * @param enc content to be decrypted</code><code> * @ return</code><code> */</code><code> public static byte[] decrypt(byte[] key, String enc) throws Exception {<!-- --></code><code> SecretKeySpec secretKey = new SecretKeySpec(key, "AES");</code><code> byte[] enCodeFormat = secretKey.getEncoded();</code><code> // Secondary encryption</code><code> SecretKeySpec secondSecretKey = new SecretKeySpec(enCodeFormat, "AES");</code>
<code> Cipher cipher = Cipher.getInstance(AES_ALGORITHM);</code><code> IvParameterSpec iv = new IvParameterSpec(key);</code><code> // Initialization</code><code> cipher.init( Cipher.DECRYPT_MODE, secondSecretKey, iv);</code><code> // First perform base64 decoding</code><code> byte[] bytes = Base64Utils.decodeFromString(enc);</code><code> // Decrypt</code><code> byte[] result = cipher.doFinal(bytes);</code><code> return result;</code><code> }</code><code> </code><code> public static void main(String[] args) throws Exception {<!-- --></code><code> //Client code</code><code> String text = "hello";</code><code> //Randomly generate a 16-digit aes key, or you can specify the 16-digit number yourself</code><code> String key = getAesKey();</code><code> System.out.println("aesKey :\
" + key);</code><code> byte[] aesKey = key.getBytes();</code>
<code> String encryptText = Base64Util.encode(AESUtil.encrypt(aesKey, text));</code><code> System.out.println("After encryption:\
" + encryptText);</code><code> String decryptText = new String(AESUtil.decrypt(aesKey, encryptText));</code><code> System.out.println("After decryption:\
" + decryptText);</code><code> }</code><code>}
public class RSAUtil{<!-- --></code>
<code> /**</code><code> * encryption algorithm RSA</code><code> */</code><code> public static final String KEY_ALGORITHM = "RSA";</code>
<code> /**</code><code> * RSA Maximum Encrypted Plaintext Size</code><code> */</code><code> private static final int MAX_ENCRYPT_BLOCK = 117;</code>
<code> /**</code><code> * RSA Maximum decrypted ciphertext size</code><code> */</code><code> private static final int MAX_DECRYPT_BLOCK = 256;</code>
<code> /**</code><code> * encryption</code><code> * @param data data</code><code> * @param publicKey publicKey</code><code> * @return byte </code><code> * @throws Exception Exception</code><code> */</code><code> public static byte[] encrypt(byte[] data, String publicKey)</code><code> throws Exception {<!-- --></code><code> byte[] keyBytes = Base64Util.decode(publicKey);</code><code> X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);</code><code> KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);</code><code> Key publicK = keyFactory.generatePublic(x509KeySpec);</code><code> Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); </code><code> cipher.init(Cipher.ENCRYPT_MODE, publicK);</code><code> int inputLen = data.length;</code><code> ByteArrayOutputStream out = new ByteArrayOutputStream();</code><code> int offSet = 0;</code><code> byte[] cache;</code><code> int i = 0;</code><code> // Sectional Encryption of Data</code> <code> while (inputLen - offSet > 0) {<!-- --></code><code> if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {<!-- --></code><code> cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);</code><code> } else {<!-- --></code><code> cache = cipher.doFinal(data, offSet, inputLen - offSet) ;</code><code> }</code><code> out.write(cache, 0, cache.length);</code><code> i + + ;</code><code> offSet = i * MAX_ENCRYPT_BLOCK;</code><code> }</code><code> byte[] encryptedData = out.toByteArray();</code><code> out.close();</code><code> return encryptedData;</code><code> }</code>
<code> /**</code><code> * Decrypt</code><code> * @param text text</code><code> * @param privateKey privateKey</code><code> * @return byte </code><code> * @throws Exception Exception</code><code> */</code><code> public static byte[] decrypt(byte[] text, String privateKey)</code><code> throws Exception {<!-- --></code><code> byte[] keyBytes = Base64Util.decode(privateKey);</code><code> PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);</code><code> KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);</code><code> Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);</code><code> Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); </code><code> cipher.init(Cipher.DECRYPT_MODE, privateK);</code><code> int inputLen = text.length;</code><code> ByteArrayOutputStream out = new ByteArrayOutputStream();</code><code> int offSet = 0;</code><code> byte[] cache;</code><code> int i = 0;</code><code> // Sectional Encryption of Data</code> <code> while (inputLen - offSet > 0) {<!-- --></code><code> if (inputLen - offSet > MAX_DECRYPT_BLOCK) {<!-- --></code><code> cache = cipher.doFinal(text, offSet, MAX_DECRYPT_BLOCK);</code><code> } else {<!-- --></code><code> cache = cipher.doFinal(text, offSet, inputLen - offSet) ;</code><code> }</code><code> out.write(cache, 0, cache.length);</code><code> i + + ;</code><code> offSet = i * MAX_DECRYPT_BLOCK;</code><code> }</code><code> byte[] decryptedData = out.toByteArray();</code><code> out.close();</code><code> return decryptedData;</code><code> }</code><code> </code><code> public static void genKeyPair() throws NoSuchAlgorithmException { </code><code> // KeyPairGenerator class is used to generate public keys and Private key pair, object generated based on RSA algorithm</code><code> KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); </code><code> </code><code> // Initialize the key pair generator , the key size is 96-2048 bits</code><code> keyPairGen.initialize(2048, new SecureRandom());</code><code> </code><code> // Generate a key pair, Save in keyPair</code><code> KeyPair keyPair = keyPairGen.generateKeyPair(); </code><code> RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // Get the private key</code><code> RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // Get the public key</code><code> </code><code> // Get the public key string</code><code> String publicKeyStr = new String(Base64.encodeBase64(publicKey.getEncoded()));</code><code> // Get the private key string</code><code> String privateKeyStr = new String(Base64.encodeBase64((privateKey.getEncoded( ))));</code><code> </code><code> System.out.println("The randomly generated public key is: " + publicKeyStr);</code><code> System.out.println ("The randomly generated private key is:" + privateKeyStr);</code><code> }</code><code> </code><code> /**</code><code> * Signature</code><code> * @param privateKey private key</code><code> * @param content content to be signed</code><code> * @return signature</code><code> */</code><code> public static String sign(String privateKey, byte[] content) {<!-- --></code><code> try {<!-- --></code><code> // The privateKey is base64 encoded, and then a private key in PKCS8 format is generated</code><code> PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64Utils.decode(privateKey.getBytes()));</code><code> KeyFactory key = KeyFactory.getInstance( "RSA");</code><code> PrivateKey priKey = key.generatePrivate(priPKCS8);</code><code> // Signature digest algorithm</code><code> Signature signature = Signature.getInstance("SHA256WithRSA ");</code><code> // Initialize this object with the private key for signing</code><code> signature.initSign(priKey);</code><code> // Use the specified byte array Update signature or verification</code><code> signature.update(content);</code><code> // Get signature byte</code><code> byte[] signed = signature.sign();</code><code> // Return with base64 encoding</code><code> return new String(Base64Utils.encode(signed));</code><code> } catch (Exception e) {<!-- - -></code><code> e.printStackTrace();</code><code> }</code><code> return null;</code><code> }</code>
<code> /**</code><code> * Signature verification</code><code> * @param publicKey public key</code><code> * @param content The content to be verified</code><code> * @param sign signature</code><code> * @return signature verification result</code><code> */</code><code> public static boolean checkSign(String publicKey, byte[] content, String sign) {<!-- --></code><code> try {<!-- --></code><code> KeyFactory keyFactory = KeyFactory.getInstance("RSA");</code><code> // Perform base64 decoding</code><code> byte[] encodedKey = Base64Utils.decodeFromString(publicKey);</code><code> // Generate public key</code><code> PublicKey pubKey = keyFactory. generatePublic(new Public key initialization signature</code><code> signature.initVerify(pubKey);</code><code> // Use the specified byte array to update the signature or verify</code><code> signature.update(content) ;</code><code> // Verify after base64 decoding</code><code> return signature.verify(Base64Utils.decodeFromString(sign));</code><code> } catch (Exception e) {< !-- --></code><code> e.printStackTrace();</code><code> }</code><code> return false;</code><code> }</code><code> </code><code> public static void main(String[] args) {<!-- --></code><code> try {<!-- --></code><code> //RSAUtil.genKeyPair();</code><code> </code><code> String text = "M6M0A4yr0Ct1i942";</code><code> System.out.println("aes password: " + text) ;</code><code> </code><code> byte[] rnt = RSAUtil.encrypt(text.getBytes(), "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmXczzPk7lcxEdyW + UDuP342QAEX3bXYFicyb9zCJdoG80Th + c0OwvvATP46W7QSQhY Pu73Gb0Y6HnaNzJschfHWFUcvXPBKrfN4RYPoU/Pf/V5Zsr0stQiQIywljwIRR9SXdjvbkgweJaQYy1xvYrjKHkKYKh + aFpc0J8fPfLNoNl97qLiK + 9UM + D8lM + uOa7UYjzq2USIuyLs83u LmZndJRd + bbkgAEq85qfjIUvKl6Do6LiXqg16CrnRQy7JDQIglmLrEm8yzQpAGcIS9kKO56gcf5xwwKg5QFFzIxHSxJP3zKX99lpljwTbUbNvtp + z6SKrHwO1h1SIgUY1wamQIDAQAB"); </code><code> // After encryption, base64 encoding</code><code> String enText = Base64Util.encode(rnt);</code><code> </code><code> System.out.println("Public key encryption: " + enText);</code><code> // First base64 transcode, then decrypt</code><code> String deText = new String(RSAUtil.decrypt( Base64Util.decode(enText), "MIIEvQIBADANBgkqhkiG9w0BAQEFAAASCBKcwggSjAgEAAoIBAQCZdzPM + TuVzER3Jb5QO4/fjZAARfdtdgWJzJv3MIl2gbzROH5zQ7C + 8BM/jpbtBJCFg + 7vcZvRjoedo3M mxyF8dYVRy9c8Eqt83hFg + hT89/9XlmyvSy1CJAjLCWPAhFH1Jd2O9uSDB4lpBjLXG9iuMoeQpgqH5oWlzQnx898s2g2X3uouIr71Qz4PyUz645rtRiPOrZRIi7Iuzze4uZmd0lF35tuSA ASrzmp + MhS8qXoOjouJeqDXoKudFDLskNAiCWYusSbzLNCkAZwhL2Qo7nqBx/nHDAqDlAUXMjEdLEk/fMpf32WmWPBNtRs2 + 2n7PpIqsfA7WHVIiBRjXBqZAgMBAAECggEADyEmVTXY/vqlYU2yRnyowXR WVwCO1RbGkwA9/A + n7av6rnGwXbK1sQ1ACIsJLBLAILmSC78ain1Pt2XOy2rkTT3Ux + ydqol4qJXIBtSAzzOv07W7v0hdDOE6kLG7SNaCsfVqs1Z5zsUmcdkvl + 9h3EKVBNipvx4l3OOq8FSH kwdBFaEtdHJNQtNd6VQJeUBItdp6Gjf3FhxidPGOpjOmHTpPseb0ElvBo + Uo0eC7xfE + phSV3OkQOk9T3yJzOiHdQIuMLnPOPQ78rfg2T1kL8l4K6muUsElDHg2mqOx2vsML3N1pbfW9r9 xR6egL0xrlnGVn5DXZCGSsble + hH + MlQKBgQDULyDUGluLCXKt1OFN2mxnwNgt5qDF4nVjMISmHvq6/ AtQ + yj67bY8by0WHk/Qo + 6wGf7auECFhBhxyNh81tiBUpwnBmM0 + yXz5Pq6LoRQg1vuPMvv8yJrn58rAnHjRClBcXFhA5P0Ue + PWXRuUTFKW4wSN7K5uMIvURnSOm0/qwKBgQC5J/09rMU JAU4EpxPJgaEVDhxrZhYGsvm35npKSjYzHJb7kM33GGN1H3nghG7wbVKZKtWqf2jlL/gIcPdteT9noyMLfWnuShNksTP2Nl5lVObaYutaYqJdGtezgXhSyqMeoX + Icwf61cdAxZQ/4/pa7Ub 0DtJ4O + mRArdT3InaywKBgAx4qKlO00qcx4zIEmYNDIocn5gzEggPg27NDz7kW0BaSB/ + Yy48gpWSw0eliHNu7zySipQ4eDJgzT8C2xabWiZfwKXajkIy8MwhDUucKFLDJcge8q2r0L4ap7RTdHYzL 2mVTWCyYSPfHQGD9H/3bbo9H0KC25Jm9aLqVWYx4PH5AoGAfKJpeiGZRFWHgeRBkovatYSZJsZCH2JMbDkNqoJH96HQFCjGLAVTtZxpevNKhjbguc + 2oh0/q77ddDkupJdQUd/jkDFspAVjBo2tz5eLdSRwf SLHEEGCz69o8SE + sGRM5yqI4X2lKnjKtlQJVfSNKrW75D8x99NEhuNQKngyp38CgYEAsF5Ah5P2QCZBo1Ittpy + 3BPT37xTcYB4zb1O6YcQ9P/9QDlcy6w/N/7CpitnlzV8ioWS4U47Lhz1 xFY0Azdm0KF8pGg8gbSBr2opUbBS9PltbYGOyfqorPaVj93pH7LJlhHOw645JIkWtPZm5iT4bbLGuydBBWJs + + GUxD35qMI= "));</code><code> </code><code> System.out.println("Private key decryption: " + deText);</code><code> </code><code> } catch (Exception e) {<!-- --></code><code> // TODO Auto-generated catch block</code><code> e.printStackTrace();</code><code> }</code><code> }</code><code>}

Picture

For use in interface projects, refer to the previous article, there is no change.

Go directly to the results:

Picture

Picture

The role of Base64 encoding

The encrypted data may not be readable, so we generally need to use the Base64 algorithm to encode the encrypted data to obtain a readable string. In other words, the return value of the AES or RSA encryption method is a Base64-encoded string, and the parameter of the AES or RSA decryption method is also a Base64-encoded string. The string is first decoded and then decrypted.

There is also an article later that introduces the differences and usage scenarios of encryption, decryption, signature, signature verification, etc., and provides corresponding examples to facilitate learning and use.

Extra: