· 7 years ago · Feb 20, 2018, 04:54 AM
1import junit.framework.TestCase;
2import org.bouncycastle.jce.provider.BouncyCastleProvider;
3import org.junit.jupiter.api.Test;
4
5import javax.crypto.Cipher;
6import javax.crypto.CipherOutputStream;
7import javax.crypto.CipherInputStream;
8import javax.crypto.KeyGenerator;
9import javax.crypto.SecretKey;
10import javax.crypto.spec.GCMParameterSpec;
11import java.io.ByteArrayInputStream;
12import java.io.ByteArrayOutputStream;
13import java.io.DataInputStream;
14import java.io.DataOutputStream;
15import java.nio.charset.Charset;
16import java.nio.charset.StandardCharsets;
17import java.security.SecureRandom;
18import java.security.Security;
19
20public class TestGCM extends TestCase {
21
22 static final String CIPHER_ALGORITHM = "AES";
23 static final String CIPHER_MODE = "GCM";
24 static final int GCM_TAG_BITS = 128;
25 static final String CIPHER_PADDING = "NoPadding";
26 // Changing the provider used to SunJCE, makes both tests pass
27 static final String PROVIDER = "BC";
28
29 static {
30 Security.addProvider(new BouncyCastleProvider());
31 }
32
33 private Cipher getCipher(int mode, SecretKey secretKey, byte[] salt, byte[] iv) throws Exception{
34
35 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM+"/"+CIPHER_MODE+"/"+CIPHER_PADDING, PROVIDER);
36 GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_BITS, iv);
37 cipher.init(mode, secretKey, spec);
38 cipher.updateAAD(salt);
39 return cipher;
40 }
41
42 private SecretKey generateKey() throws Exception{
43 KeyGenerator keyGen = KeyGenerator.getInstance(CIPHER_ALGORITHM, PROVIDER);
44 keyGen.init(128);
45 return keyGen.generateKey();
46 }
47 @Test
48 public void encryptAndDecryptWithCipherStream() throws Exception {
49 byte[] secretBytes = "This is a random message to remain secret".getBytes(StandardCharsets.UTF_8);
50 SecureRandom random = new SecureRandom();
51 byte[] salt = new byte[64];
52 random.nextBytes(salt);
53 byte[] iv = new byte[12];
54 random.nextBytes(iv);
55 SecretKey secretKey = generateKey();
56
57 // First encrypt
58 Cipher encryptionCipher = getCipher(Cipher.ENCRYPT_MODE, secretKey, salt, iv);
59 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
60 try (CipherOutputStream cipherStream = new CipherOutputStream(bytes, encryptionCipher);
61 DataOutputStream output = new DataOutputStream(cipherStream)) {
62 output.writeInt(secretBytes.length);
63 output.write(secretBytes);
64 }
65 byte[] encryptedBytes = bytes.toByteArray();
66
67 // Now decrypt
68 Cipher decryptionCipher = getCipher(Cipher.DECRYPT_MODE, secretKey, salt, iv);
69 try (ByteArrayInputStream bytesStream = new ByteArrayInputStream(encryptedBytes);
70 CipherInputStream cipherStream = new CipherInputStream(bytesStream, decryptionCipher);
71 DataInputStream input = new DataInputStream(cipherStream)) {
72 int expectedLength = input.readInt();
73 byte[] decryptedBytes = new byte[expectedLength];
74 assertEquals(expectedLength, input.read(decryptedBytes));
75 }
76 }
77
78 @Test
79 public void encryptandDecryptWithoutCipherStream() throws Exception {
80
81 byte[] secretBytes = "This is a random message to remain secret".getBytes(Charset
82 .defaultCharset());
83 SecureRandom random = new SecureRandom();
84 byte[] salt = new byte[64];
85 random.nextBytes(salt);
86 byte[] iv = new byte[12];
87 random.nextBytes(iv);
88 SecretKey secretKey = generateKey();
89
90 // First encrypt
91 Cipher encryptionCipher = getCipher(Cipher.ENCRYPT_MODE, secretKey, salt, iv);
92 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
93 try (DataOutputStream output = new DataOutputStream(bytes)) {
94 output.writeInt(secretBytes.length);
95 output.write(secretBytes);
96 }
97 byte[] encryptedBytes = encryptionCipher.doFinal(bytes.toByteArray());
98
99 // Then decrypt
100 Cipher decryptionCipher = getCipher(Cipher.DECRYPT_MODE, secretKey, salt, iv);
101 byte[] decryptedBytes = decryptionCipher.doFinal(encryptedBytes);
102 try (ByteArrayInputStream bytesStream = new ByteArrayInputStream(decryptedBytes);
103 DataInputStream input = new DataInputStream(bytesStream)) {
104 int expectedLength = input.readInt();
105 byte[] decryptedSecretBytes = new byte[expectedLength];
106 assertEquals(expectedLength, input.read(decryptedSecretBytes));
107 }
108 }
109
110 @Test
111 public void encryptWithCipherStreamAndDecryptWithout() throws Exception {
112 byte[] secretBytes = "This is a random message to remain secret".getBytes(Charset
113 .defaultCharset());
114 SecureRandom random = new SecureRandom();
115 byte[] salt = new byte[64];
116 random.nextBytes(salt);
117 byte[] iv = new byte[12];
118 random.nextBytes(iv);
119 SecretKey secretKey = generateKey();
120
121 // First encrypt
122 Cipher encryptionCipher = getCipher(Cipher.ENCRYPT_MODE, secretKey, salt, iv);
123 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
124 try (CipherOutputStream cipherStream = new CipherOutputStream(bytes, encryptionCipher);
125 DataOutputStream output = new DataOutputStream(cipherStream)) {
126 output.writeInt(secretBytes.length);
127 output.write(secretBytes);
128 }
129 byte[] encryptedBytes = bytes.toByteArray();
130
131 // Then decrypt
132 Cipher decryptionCipher = getCipher(Cipher.DECRYPT_MODE, secretKey, salt, iv);
133 byte[] decryptedBytes = decryptionCipher.doFinal(encryptedBytes);
134 try (ByteArrayInputStream bytesStream = new ByteArrayInputStream(decryptedBytes);
135 DataInputStream input = new DataInputStream(bytesStream)) {
136 int expectedLength = input.readInt();
137 byte[] decryptedSecretBytes = new byte[expectedLength];
138 assertEquals(expectedLength, input.read(decryptedSecretBytes));
139 }
140 }
141
142 @Test
143 public void encryptWithoutCipherStreamAndDecryptWith() throws Exception {
144 byte[] secretBytes = "This is a random message to remain secret".getBytes(Charset
145 .defaultCharset());
146 SecureRandom random = new SecureRandom();
147 byte[] salt = new byte[64];
148 random.nextBytes(salt);
149 byte[] iv = new byte[12];
150 random.nextBytes(iv);
151 SecretKey secretKey = generateKey();
152
153 // First encrypt
154 Cipher encryptionCipher = getCipher(Cipher.ENCRYPT_MODE, secretKey, salt, iv);
155 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
156 try (DataOutputStream output = new DataOutputStream(bytes)) {
157 output.writeInt(secretBytes.length);
158 output.write(secretBytes);
159 }
160 byte[] encryptedBytes = encryptionCipher.doFinal(bytes.toByteArray());
161
162 // Now decrypt
163 Cipher decryptionCipher = getCipher(Cipher.DECRYPT_MODE, secretKey, salt, iv);
164 try (ByteArrayInputStream bytesStream = new ByteArrayInputStream(encryptedBytes);
165 CipherInputStream cipherStream = new CipherInputStream(bytesStream, decryptionCipher);
166 DataInputStream input = new DataInputStream(cipherStream)) {
167 int expectedLength = input.readInt();
168 byte[] decryptedBytes = new byte[expectedLength];
169 assertEquals(expectedLength, input.read(decryptedBytes));
170 }
171 }
172}