· 7 years ago · Apr 17, 2018, 07:02 PM
1package org.cloudfoundry.identity.uaa.cypto;
2
3import org.bouncycastle.crypto.digests.SHA256Digest;
4import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
5import org.bouncycastle.crypto.params.KeyParameter;
6import org.junit.Test;
7
8import javax.crypto.Cipher;
9import javax.crypto.CipherInputStream;
10import javax.crypto.CipherOutputStream;
11import javax.crypto.SecretKey;
12import javax.crypto.spec.GCMParameterSpec;
13import javax.crypto.spec.SecretKeySpec;
14import java.io.FileInputStream;
15import java.io.FileOutputStream;
16import java.io.IOException;
17import java.io.UnsupportedEncodingException;
18import java.security.GeneralSecurityException;
19import java.security.NoSuchAlgorithmException;
20import java.security.SecureRandom;
21
22public class EncryptionKeyServiceTest {
23
24 @Test
25 public void spike() throws GeneralSecurityException, UnsupportedEncodingException {
26// encrypt("some-password", "/tmp/lol");
27 decrypt("some-password", "/tmp/lol.enc");
28 }
29
30 private static byte[] generateRandomArry(int sizeInBytes) throws NoSuchAlgorithmException {
31 /* generate random salt */
32 final byte[] salt = new byte[sizeInBytes];
33 SecureRandom random = SecureRandom.getInstanceStrong();
34 random.nextBytes(salt);
35 return salt;
36 }
37
38 private static final int DEFAULT_GCM_AUTHENTICATION_TAG_SIZE_BITS = 128;
39
40 private static final int DEFAULT_GCM_IV_NONCE_SIZE_BYTES = 12;
41 private static final int DEFAULT_PBKDF2_ITERATIONS = 65536;
42 private static final int DEFAULT_PBKDF2_SALT_SIZE_BYTES = 32;
43
44 private static final int DEFAULT_AES_KEY_LENGTH_BITS = 256;
45 private static final String DEFAULT_CIPHER = "AES";
46 private static final String DEFAULT_CIPHERSCHEME = "AES/GCM/NoPadding";
47 private static final String DEFAULT_PBKDF2_SCHEME = "PBKDF2WithHmacSHA256";
48 private int gcmAuthenticationTagSizeBits = DEFAULT_GCM_AUTHENTICATION_TAG_SIZE_BITS;
49 private int gcmIvNonceSizeBytes = DEFAULT_GCM_IV_NONCE_SIZE_BYTES;
50 private int pbkdf2Iterations = DEFAULT_PBKDF2_ITERATIONS;
51 private int pbkdf2SaltSizeBytes = DEFAULT_PBKDF2_SALT_SIZE_BYTES;
52 private int aesKeyLengthBits = DEFAULT_AES_KEY_LENGTH_BITS;
53 private String cipher = DEFAULT_CIPHER;
54 private String cipherscheme = DEFAULT_CIPHERSCHEME;
55 private String pbkdf2Scheme = DEFAULT_PBKDF2_SCHEME;
56
57
58 public byte[] generateBouncyKey(byte[] salt) throws UnsupportedEncodingException, NoSuchAlgorithmException {
59 PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest());
60
61 gen.init("some-password".getBytes("UTF-8"), salt, 4096);
62 return ((KeyParameter) gen.generateDerivedParameters(128)).getKey();
63 }
64
65 public byte[] encrypt(String password, String path, String plaintext) throws GeneralSecurityException, IOException {
66 /* Derive the key*/
67// SecretKeyFactory factory = SecretKeyFactory.getInstance(pbkdf2Scheme);
68// byte[] newSalt = generateRandomArry(pbkdf2SaltSizeBytes);
69// KeySpec keyspec = new PBEKeySpec(password.toCharArray(), newSalt, pbkdf2Iterations, aesKeyLengthBits);
70// SecretKey tmp = factory.generateSecret(keyspec);
71
72// SecretKey key = new SecretKeySpec(tmp.getEncoded(), cipher);
73
74 byte[] newSalt = generateRandomArry(pbkdf2SaltSizeBytes);
75 newSalt = Strings.repeat("a", pbkdf2SaltSizeBytes).getBytes();
76
77 SecretKey key = new SecretKeySpec(generateBouncyKey(newSalt), cipher);
78
79 Cipher myCipher = Cipher.getInstance(cipherscheme);
80 byte[] newNonce = generateRandomArry(gcmIvNonceSizeBytes);
81 newNonce = Strings.repeat("b", gcmIvNonceSizeBytes).getBytes();
82
83
84 GCMParameterSpec spec = new GCMParameterSpec(gcmAuthenticationTagSizeBits, newNonce);
85 myCipher.init(Cipher.ENCRYPT_MODE, key, spec);
86
87 try (
88 ByteArrayInputStream fileInputStream = new ByteArrayInputStream(plaintext.getBytes());
89 ByteArrayOutputStream fileOutputStream = new ByteArrayOutputStream();
90 CipherOutputStream encryptedOutputStream = new CipherOutputStream(fileOutputStream, myCipher);
91 ) {
92 // write IV/nonce
93 fileOutputStream.write(newNonce);
94
95 // write salt
96 fileOutputStream.write(newSalt);
97
98
99 byte[] buffer = new byte[32];
100 while (fileInputStream.read(buffer) > 0) {
101 encryptedOutputStream.write(buffer);
102 }
103 encryptedOutputStream.flush();
104 encryptedOutputStream.close();
105 return fileOutputStream.toByteArray();
106 } catch (IOException e) {
107 throw new SecurityException(e.getMessage(), e);
108 }
109
110// return Files.readAllBytes(Paths.get(path + ".enc"));
111 }
112
113
114 public byte[] decrypt(String password, String path, byte[] encrypt) throws GeneralSecurityException, UnsupportedEncodingException {
115
116 // Read configuration from file
117
118 byte[] myNonce = new byte[gcmIvNonceSizeBytes];
119 byte[] mySalt = new byte[pbkdf2SaltSizeBytes];
120
121 try (
122 ByteArrayInputStream fileInputStream = new ByteArrayInputStream(encrypt);
123 ) {
124 int countReadBytesNonce = fileInputStream.read(myNonce);
125 int countReadBytesSalt = fileInputStream.read(mySalt);
126 } catch (IOException e) {
127 throw new SecurityException(e.getMessage(), e);
128 }
129 System.out.println(String.format("|||%s|||", new String(mySalt)));
130 System.out.println(String.format("|||%s|||", new String(myNonce)));
131
132 /* Derive the key*/
133// SecretKeyFactory factory = SecretKeyFactory.getInstance(pbkdf2Scheme);
134// KeySpec keyspec = new PBEKeySpec(password.toCharArray(), mySalt, pbkdf2Iterations, aesKeyLengthBits);
135// SecretKey tmp = factory.generateSecret(keyspec);
136// SecretKey key = new SecretKeySpec(tmp.getEncoded(), cipher);
137 SecretKey key = new SecretKeySpec(generateBouncyKey(mySalt), cipher);
138
139 Cipher myCipher = Cipher.getInstance(cipherscheme);
140 GCMParameterSpec spec = new GCMParameterSpec(gcmAuthenticationTagSizeBits, myNonce);
141
142 myCipher.init(Cipher.DECRYPT_MODE, key, spec);
143
144 try (
145 ByteArrayOutputStream fileOutputStream = new ByteArrayOutputStream();
146 ByteArrayInputStream fileInputStream1 = new ByteArrayInputStream(encrypt);
147 CipherInputStream cipherInputStream = new CipherInputStream(fileInputStream1, myCipher);
148 ) {
149 // offset the stream by the bytes already read previosly
150
151 byte[] skipped = new byte[gcmIvNonceSizeBytes + pbkdf2SaltSizeBytes];
152 int read = fileInputStream1.read(skipped);
153// cipherInputStream.skip(gcmIvNonceSizeBytes + pbkdf2SaltSizeBytes);
154
155 byte[] buffer = new byte[32];
156 while (cipherInputStream.read(buffer) > 0) {
157 fileOutputStream.write(buffer);
158 }
159
160 return fileOutputStream.toByteArray();
161 } catch (IOException e) {
162 throw new SecurityException(e.getMessage(), e);
163 }
164 }
165}