Last active
September 13, 2022 21:06
-
-
Save marcelmaatkamp/15bb8949ff145aa9f376 to your computer and use it in GitHub Desktop.
AES(256) wrapped in RSA(2048) example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.io.Serializable; | |
| /** | |
| * Created by marcelmaatkamp (m.maatkamp@gmail.com) | |
| */ | |
| public class Data implements Serializable { | |
| public String msg; | |
| public Data(String s) { | |
| this.msg = s; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import org.apache.commons.lang3.builder.ReflectionToStringBuilder; | |
| import org.bouncycastle.util.encoders.Base64; | |
| import java.io.Serializable; | |
| import java.lang.reflect.Field; | |
| /** | |
| * Created by marcelmaatkamp (m.maatkamp@gmail.com) | |
| */ | |
| public class EncryptedData implements Serializable { | |
| public byte[] signature; | |
| public byte[] encryptedKey; | |
| public byte[] encryptedData; | |
| public byte[] iv; | |
| public String toString() { | |
| return (new ReflectionToStringBuilder(this) { | |
| protected Object getValue(Field f) throws IllegalAccessException { | |
| if ("signature".equals(f.getName())) { | |
| return Base64.toBase64String(signature); | |
| } else if ("encryptedKey".equals(f.getName())) { | |
| return Base64.toBase64String(encryptedKey); | |
| } else if ("encryptedData".equals(f.getName())) { | |
| return Base64.toBase64String(encryptedData); | |
| } else if ("iv".equals(f.getName())) { | |
| return Base64.toBase64String(encryptedData); | |
| } else { | |
| return super.getValue(f); | |
| } | |
| } | |
| }).toString(); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package security; | |
| import org.bouncycastle.crypto.digests.SHA256Digest; | |
| import org.bouncycastle.jce.provider.BouncyCastleProvider; | |
| import org.bouncycastle.util.encoders.Base64; | |
| import org.junit.Assert; | |
| import org.junit.Test; | |
| import org.slf4j.Logger; | |
| import org.slf4j.LoggerFactory; | |
| import org.springframework.util.SerializationUtils; | |
| import security.model.Data; | |
| import security.model.EncryptedData; | |
| import javax.crypto.*; | |
| import javax.crypto.spec.IvParameterSpec; | |
| import java.io.IOException; | |
| import java.security.*; | |
| import java.security.spec.InvalidKeySpecException; | |
| /** | |
| * Created by marcelmaatkamp (m.maatkamp@gmail.com) | |
| */ | |
| public class RSAWithAESAndCBCWithIVsAndDigestTest { | |
| /** | |
| * AES(256) wrapped in RSA(2048) example | |
| * sends data encrypted from client to server | |
| */ | |
| @Test | |
| public void testRSAWithAESAndCBCWithIVs() throws InvalidKeyException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, SignatureException, NoSuchProviderException, InvalidKeySpecException, NoSuchPaddingException, IOException, InvalidAlgorithmParameterException { | |
| Security.addProvider(new BouncyCastleProvider()); | |
| String ALGORITHM_SIGNATURE = "SHA1withRSA"; | |
| // bouncycastle provider | |
| String SECURITY_PROVIDER = "BC"; | |
| // RSA settings | |
| String ALGORITHM_RSA = "RSA"; | |
| String ALGORITHM_RSA_CIPHER = "RSA/None/NoPadding"; | |
| int ALGORITHM_RSA_KEYSIZE = 2048; | |
| // AES settings | |
| String ALGORITHM_AES = "AES"; | |
| String ALGORITHM_AES_CIPHER = "AES/CBC/PKCS7Padding"; | |
| int ALGORITHM_AES_KEYSIZE = 256; | |
| // ------ | |
| // CLIENT | |
| // ------ | |
| // RSA: pub/priv keys | |
| KeyPairGenerator keyPairGeneratorClient = KeyPairGenerator.getInstance(ALGORITHM_RSA); | |
| keyPairGeneratorClient.initialize(ALGORITHM_RSA_KEYSIZE); | |
| KeyPair keyPairClient = keyPairGeneratorClient.generateKeyPair(); | |
| PrivateKey privateKeyClient = keyPairClient.getPrivate(); | |
| PublicKey publicKeyClient = keyPairClient.getPublic(); | |
| Cipher cipherClient = Cipher.getInstance(ALGORITHM_RSA_CIPHER, SECURITY_PROVIDER); | |
| // AES: symmetrical | |
| KeyGenerator keyGeneratorSymmetricalKeyClient = KeyGenerator.getInstance(ALGORITHM_AES); | |
| keyGeneratorSymmetricalKeyClient.init(ALGORITHM_AES_KEYSIZE); | |
| SecretKey symmetricalKeyClient = keyGeneratorSymmetricalKeyClient.generateKey(); | |
| Cipher cipherSymmetricalKeyClient = Cipher.getInstance(ALGORITHM_AES_CIPHER, SECURITY_PROVIDER); | |
| // signature | |
| SecureRandom secureRandomClient = new SecureRandom(); | |
| SHA256Digest sha256DigestClient = new SHA256Digest(); | |
| Signature signatureClient = Signature.getInstance(ALGORITHM_SIGNATURE); | |
| // ------ | |
| // SERVER | |
| // ------ | |
| // RSA: pub/priv keys | |
| KeyPairGenerator keyPairGeneratorServer = KeyPairGenerator.getInstance(ALGORITHM_RSA); | |
| keyPairGeneratorServer.initialize(ALGORITHM_RSA_KEYSIZE); | |
| KeyPair keyPairServer = keyPairGeneratorServer.generateKeyPair(); | |
| PrivateKey privateKeyServer = keyPairServer.getPrivate(); | |
| PublicKey publicKeyServer = keyPairServer.getPublic(); | |
| Cipher cipherServer = Cipher.getInstance(ALGORITHM_RSA_CIPHER, SECURITY_PROVIDER); | |
| // AES: symmetrical | |
| KeyGenerator keyGeneratorSymmetricalKeyServer = KeyGenerator.getInstance(ALGORITHM_AES); | |
| keyGeneratorSymmetricalKeyServer.init(ALGORITHM_AES_KEYSIZE); | |
| // SecretKey symmetricalKeyServer = keyGeneratorSymmetricalKeyServer.generateKey(); | |
| Cipher cipherSymmetricalKeyServer = Cipher.getInstance(ALGORITHM_AES_CIPHER, SECURITY_PROVIDER); | |
| // signature | |
| SHA256Digest sha256DigestServer = new SHA256Digest(); | |
| Signature signatureServer = Signature.getInstance(ALGORITHM_SIGNATURE); | |
| // ------------- | |
| // on the client | |
| // ------------- | |
| String text = "encrypt me!"; | |
| byte[] plain = SerializationUtils.serialize(new Data(text)); | |
| EncryptedData encryptedData = new EncryptedData(); | |
| // calculate digest | |
| byte[] digest = new byte[sha256DigestClient.getDigestSize()]; | |
| sha256DigestClient.update(plain, 0, plain.length); | |
| sha256DigestClient.doFinal(digest, 0); | |
| // sign the digest | |
| signatureClient.initSign(privateKeyClient); | |
| signatureClient.update(digest); | |
| encryptedData.signature = signatureClient.sign(); | |
| // crypt text | |
| IvParameterSpec ivParameterClient = new IvParameterSpec(secureRandomClient.generateSeed(16)); | |
| cipherSymmetricalKeyServer.init(Cipher.ENCRYPT_MODE, symmetricalKeyClient, ivParameterClient); | |
| encryptedData.encryptedData = cipherSymmetricalKeyServer.doFinal(plain); | |
| encryptedData.iv = ivParameterClient.getIV(); | |
| // crypt aes key | |
| cipherClient.init(Cipher.WRAP_MODE, publicKeyServer); | |
| encryptedData.encryptedKey = cipherClient.wrap(symmetricalKeyClient); | |
| // -------------- | |
| // transportation | |
| // -------------- | |
| EncryptedData serializedEncryptedData = | |
| (EncryptedData) SerializationUtils.deserialize( | |
| SerializationUtils.serialize(encryptedData)); | |
| // ------------- | |
| // on the server | |
| // ------------- | |
| // unwrap aes key | |
| cipherServer.init(Cipher.UNWRAP_MODE, privateKeyServer); | |
| SecretKey decryptedKey = (SecretKey) cipherServer.unwrap( | |
| serializedEncryptedData.encryptedKey, "AES", Cipher.SECRET_KEY); | |
| // decrypt text | |
| IvParameterSpec ivParameterSpecServer = new IvParameterSpec(encryptedData.iv); | |
| cipherSymmetricalKeyClient.init(Cipher.DECRYPT_MODE, decryptedKey, ivParameterSpecServer); | |
| byte[] decyptedData = cipherSymmetricalKeyClient.doFinal(serializedEncryptedData.encryptedData); | |
| // calculate digest | |
| byte[] digestServer = new byte[sha256DigestServer.getDigestSize()]; | |
| sha256DigestServer.update(decyptedData, 0, decyptedData.length); | |
| sha256DigestServer.doFinal(digestServer, 0); | |
| // verify signature from digest | |
| signatureServer.initVerify(publicKeyClient); | |
| signatureServer.update(digestServer); | |
| // validate signature | |
| Assert.assertTrue("valid signature(" + Base64.toBase64String(serializedEncryptedData.signature) + ") from client", signatureServer.verify(serializedEncryptedData.signature)); | |
| // validate decrypted text | |
| if (signatureServer.verify(serializedEncryptedData.signature)) { | |
| Data decryptedData = (Data) SerializationUtils.deserialize(decyptedData); | |
| Assert.assertEquals("decypted text same as original", decryptedData.msg, text); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment