1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.common.util.encrypt.openssl;
17
18 import static com.google.common.base.Preconditions.checkArgument;
19 import static com.google.common.collect.Lists.newArrayList;
20 import static java.lang.System.arraycopy;
21 import static org.kuali.common.util.Ascii.isDigit;
22 import static org.kuali.common.util.Ascii.isLetter;
23 import static org.kuali.common.util.base.Exceptions.illegalArgument;
24 import static org.kuali.common.util.base.Precondition.checkNotNull;
25 import static org.kuali.common.util.encrypt.openssl.OpenSSLContext.buildOpenSSLContext;
26
27 import java.security.MessageDigest;
28 import java.security.NoSuchAlgorithmException;
29 import java.security.SecureRandom;
30 import java.util.List;
31 import java.util.Random;
32
33 import org.kuali.common.util.encrypt.EncryptionContext;
34
35 import com.google.common.collect.ImmutableList;
36
37 public class OpenSSL {
38
39 private static final Random RANDOM = new SecureRandom();
40 private static final int DEFAULT_SALT_SIZE = 8;
41
42
43 private static final int DEFAULT_PASSWORD_LENGTH = 22;
44 private static final List<Character> DEFAULT_PASSWORD_CHARS = getAlphaNumericCharacters();
45
46
47
48
49 public static String generatePassword() {
50 return generatePassword(DEFAULT_PASSWORD_LENGTH);
51 }
52
53
54
55
56 public static String generatePassword(int length) {
57 return generatePassword(DEFAULT_PASSWORD_CHARS, length);
58 }
59
60 public static String generatePassword(List<Character> chars, int length) {
61 return generatePassword(chars, length, RANDOM);
62 }
63
64 public static String generatePassword(List<Character> chars, int length, Random random) {
65 char[] buffer = new char[length];
66 int size = chars.size();
67 for (int i = 0; i < length; i++) {
68 buffer[i] = chars.get(random.nextInt(size));
69 }
70 return new String(buffer);
71 }
72
73 public static OpenSSLEncryptor buildOpenSSLEncryptor(EncryptionContext context) {
74 OpenSSLContext osc = buildOpenSSLContext(context.getStrength());
75 return new OpenSSLEncryptor(osc, context.getPassword());
76 }
77
78 public static byte[] combineByteArrays(byte[]... arrays) {
79 byte[] bytes = allocateByteArray(arrays);
80 int offset = 0;
81 for (byte[] array : arrays) {
82 offset = addByteArray(bytes, array, offset);
83 }
84 return bytes;
85 }
86
87 public static int addByteArray(byte[] dst, byte[] src, int offset) {
88 arraycopy(src, 0, dst, offset, src.length);
89 return offset + src.length;
90 }
91
92 public static byte[] allocateByteArray(byte[]... arrays) {
93 int length = 0;
94 for (byte[] array : arrays) {
95 length += array.length;
96 }
97 return new byte[length];
98 }
99
100
101
102
103 public static byte[] createSalt() {
104 return createSalt(DEFAULT_SALT_SIZE);
105 }
106
107
108
109
110 public static byte[] createSalt(int length) {
111 byte[] salt = new byte[length];
112 RANDOM.nextBytes(salt);
113 return salt;
114 }
115
116 public static final byte[] toByteArray(List<Byte> bytes) {
117 byte[] array = new byte[bytes.size()];
118 for (int i = 0; i < array.length; i++) {
119 array[i] = bytes.get(i);
120 }
121 return array;
122 }
123
124 public static ImmutableList<Byte> toByteList(byte[] original) {
125 return toByteList(original, 0, original.length);
126 }
127
128 public static ImmutableList<Byte> toByteList(byte[] original, int offset, int length) {
129 List<Byte> list = newArrayList();
130 for (int i = offset; i < length; i++) {
131 list.add(original[i]);
132 }
133 return ImmutableList.copyOf(list);
134 }
135
136 public static String checkBase64(String text) {
137 checkNotNull(text, "text");
138 for (char c : text.toCharArray()) {
139 checkArgument(isBase64(c), "'%s' is not a base 64 character", c);
140 }
141 return text;
142 }
143
144 public static boolean isBase64(char c) {
145 if (isLetter(c) || isDigit(c)) {
146 return true;
147 } else {
148 return c == '/' || c == '+' || c == '=';
149 }
150 }
151
152 public static MessageDigest getMessageDigest(String algorithm) {
153 try {
154 return MessageDigest.getInstance(algorithm);
155 } catch (NoSuchAlgorithmException e) {
156 throw illegalArgument(e);
157 }
158
159 }
160
161 public static OpenSSLEncryptedContext buildEncryptedContext(OpenSSLContext context, int initVectorLength, byte[] salt, byte[] data) {
162 MessageDigest md = getMessageDigest(context.getDigestAlgorithm());
163 int keyLength = context.getKeySizeBits() / Byte.SIZE;
164 byte[] key = new byte[keyLength];
165 int keyIndex = 0;
166 byte[] initVector = new byte[initVectorLength];
167 int initVectorIndex = 0;
168 byte[] md_buf = null;
169 int nkey = keyLength;
170 int niv = initVectorLength;
171 int i = 0;
172 int addmd = 0;
173 for (;;) {
174 md.reset();
175 if (addmd++ > 0) {
176 md.update(md_buf);
177 }
178 md.update(data);
179 if (null != salt) {
180 md.update(salt, 0, 8);
181 }
182 md_buf = md.digest();
183 for (i = 1; i < context.getIterations(); i++) {
184 md.reset();
185 md.update(md_buf);
186 md_buf = md.digest();
187 }
188 i = 0;
189 if (nkey > 0) {
190 for (;;) {
191 if (nkey == 0)
192 break;
193 if (i == md_buf.length)
194 break;
195 key[keyIndex++] = md_buf[i];
196 nkey--;
197 i++;
198 }
199 }
200 if (niv > 0 && i != md_buf.length) {
201 for (;;) {
202 if (niv == 0)
203 break;
204 if (i == md_buf.length)
205 break;
206 initVector[initVectorIndex++] = md_buf[i];
207 niv--;
208 i++;
209 }
210 }
211 if (nkey == 0 && niv == 0) {
212 break;
213 }
214 }
215 for (i = 0; i < md_buf.length; i++) {
216 md_buf[i] = 0;
217 }
218
219 OpenSSLEncryptedContext.Builder builder = OpenSSLEncryptedContext.builder();
220 builder.withSalt(toByteList(salt));
221 builder.withKey(toByteList(key));
222 builder.withInitVector(toByteList(initVector));
223 return builder.build();
224 }
225
226 protected static List<Character> getAlphaNumericCharacters() {
227 List<Character> chars = newArrayList();
228 for (char c = 'A'; c < 'Z'; c++) {
229 chars.add(c);
230 }
231 for (char c = 'a'; c < 'z'; c++) {
232 chars.add(c);
233 }
234 for (char c = '0'; c < '9'; c++) {
235 chars.add(c);
236 }
237 return ImmutableList.copyOf(chars);
238 }
239
240 }