· 6 years ago · Feb 05, 2019, 02:12 PM
1package com.krybjavalib;
2
3import android.content.Context;
4import android.os.Build;
5import android.security.KeyPairGeneratorSpec;
6import android.security.keystore.KeyGenParameterSpec;
7import android.security.keystore.KeyProperties;
8import android.util.Base64;
9import android.util.Log;
10
11import java.math.BigInteger;
12import java.security.KeyFactory;
13import java.security.KeyPair;
14import java.security.KeyPairGenerator;
15import java.security.KeyStore;
16import java.security.PrivateKey;
17import java.security.Provider;
18import java.security.PublicKey;
19import java.security.Security;
20import java.security.spec.X509EncodedKeySpec;
21import java.util.Calendar;
22import java.util.Set;
23
24import javax.crypto.Cipher;
25import javax.crypto.KeyGenerator;
26import javax.crypto.SecretKey;
27import javax.security.auth.x500.X500Principal;
28
29/**
30 * This class needed for generation RSA key in android app for future using in OpenSSL.
31 */
32public final class KeyStoreConnector {
33 private static final int ADD_YEAR_AMOUNT = 20;
34 private Context mContext;
35 private final String cipherMode = "RSA/ECB/PKCS1Padding";
36 private Calendar startDate;
37 private Calendar endDate;
38 private X500Principal principal;
39 private final String keyStoreName = "AndroidKeyStore";
40 private KeyStore keyStore;
41
42 KeyStoreConnector(final Context context) {
43 this.mContext = context;
44 this.createKeyStore();
45 if (getAsymKeyPair(keyStoreName) == null) {
46 generateASymKeypair(keyStoreName);
47 }
48 }
49
50 /**
51 * Create Android Keystore or load.
52 */
53 private void createKeyStore() {
54 try {
55 this.keyStore = KeyStore.getInstance(keyStoreName);
56 this.keyStore.load(null);
57 } catch (Exception err) {
58 Log.d("KSC", "createKeyStore " + err.getMessage());
59 }
60 }
61
62 /**
63 * Need to be called before generating CA or keypair.
64 */
65 private void initRSASettings(final String alias) {
66 startDate = Calendar.getInstance();
67 endDate = Calendar.getInstance();
68
69 principal = new X500Principal("CN=" + alias + " CA Certificate");
70 }
71
72 /**
73 * Remove keys from the KeyStore.
74 *
75 * @param alias key alias that need to be removed.
76 */
77 public void removeKey(final String alias) {
78 try {
79 this.keyStore.deleteEntry(alias);
80 } catch (Exception err) {
81 Log.d("KSC", "removeKey " + err.getMessage());
82 }
83 }
84
85 /**
86 * Get the public and private key.
87 *
88 * @param alias key alias
89 * @return Generated KeyPair.
90 */
91 private KeyPair getAsymKeyPair(final String alias) {
92 KeyPair generatedKeyPair = null;
93 try {
94 final PrivateKey privKey = (PrivateKey) keyStore.getKey(alias, null);
95 final PublicKey pubKey = keyStore.getCertificate(alias).getPublicKey();
96 if (privKey != null && pubKey != null) {
97 generatedKeyPair = new KeyPair(pubKey, privKey);
98 }
99 } catch (Exception err) {
100 Log.d("KSC", "getAsymKeyPair " + err.getMessage());
101 }
102
103 return generatedKeyPair;
104 }
105
106 /**
107 * Create keypair (Public, Private) with self-signed certificate.
108 *
109 * @param generator provided generator
110 */
111 private void initGeneratorKeySpecs(final KeyPairGenerator generator, final String alias) {
112 initRSASettings(alias);
113 endDate.add(Calendar.YEAR, ADD_YEAR_AMOUNT);
114
115 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
116
117 final KeyPairGeneratorSpec builder = new KeyPairGeneratorSpec.Builder(this.mContext)
118 .setAlias(alias)
119 .setSerialNumber(BigInteger.ONE)
120 .setSubject(this.principal)
121 .setStartDate(startDate.getTime())
122 .setEndDate(endDate.getTime())
123 .build();
124
125 try {
126 generator.initialize(builder);
127 } catch (Exception err) {
128 Log.d("KSC", "initGeneratorKeySpecs preM " + err.getMessage());
129 }
130
131 } else {
132
133 final KeyGenParameterSpec builder = new KeyGenParameterSpec.Builder(alias,
134 KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_ENCRYPT)
135 .setBlockModes(KeyProperties.BLOCK_MODE_ECB)
136 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
137 .build();
138
139 try {
140 generator.initialize(builder);
141 } catch (Exception err) {
142 Log.d("KSC", "initGeneratorKeySpecs postM " + err.getMessage());
143 }
144 }
145 }
146
147 /**
148 * Create RSA public and private key.
149 *
150 * @param alias Key alias
151 * @return Generated Keypair
152 */
153 KeyPair generateASymKeypair(final String alias) {
154 KeyPair generatedKeyPair = null;
155 try {
156 final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", keyStoreName);
157 this.initGeneratorKeySpecs(generator, alias);
158
159 generatedKeyPair = generator.generateKeyPair();
160 } catch (Exception err) {
161 Log.d("KSC", "generateASymKeypair " + err.getMessage());
162 }
163
164 return generatedKeyPair;
165 }
166
167 /**
168 * Encrypt small amounts of data.
169 *
170 * @param data Information that will be encrypted
171 * @param alias alias of key
172 * @return Encrypted string.
173 */
174 public String encrypt(final String data, final String alias) {
175 String localAlias = alias;
176 if (localAlias == null) {
177 localAlias = keyStoreName;
178 }
179 final Cipher crypto;
180 String encodedString = null;
181 try {
182 final KeyPair pair = this.getAsymKeyPair(localAlias);
183
184 crypto = Cipher.getInstance(this.cipherMode);
185 crypto.init(Cipher.ENCRYPT_MODE, pair.getPublic());
186 final byte[] bytes = crypto.doFinal(data.getBytes("UTF-8"));
187 encodedString = Base64.encodeToString(bytes, Base64.NO_WRAP);
188 } catch (Exception err) {
189 Log.d("KSC", "encrypt string " + err.getMessage());
190 }
191
192 return encodedString;
193 }
194
195 /**
196 * Encrypt small amounts of data.
197 *
198 * @param data data for encrypting
199 * @param alias key alias
200 * @return Encrypted data
201 */
202 public byte[] encrypt(final byte[] data, final String alias) {
203 String localAlias = alias;
204 if (localAlias == null) {
205 localAlias = keyStoreName;
206 }
207 final Cipher crypto;
208 byte[] encryptedBytes = null;
209 try {
210 final KeyPair pair = this.getAsymKeyPair(localAlias);
211
212 crypto = Cipher.getInstance(this.cipherMode);
213 crypto.init(Cipher.ENCRYPT_MODE, pair.getPublic());
214 encryptedBytes = crypto.doFinal(data);
215 } catch (Exception err) {
216 Log.d("KSC", "encrypt byte " + err.getMessage());
217 }
218
219 return encryptedBytes;
220 }
221
222 /**
223 * Encrypt data with a specific public key.
224 *
225 * @param key Public key for encryption
226 * @param data Data to be encrypted
227 * @return Encrypted string
228 */
229 public String encrypt(final PublicKey key, final String data) {
230 final Cipher crypto;
231 String encString = null;
232 try {
233 crypto = Cipher.getInstance(this.cipherMode);
234 crypto.init(Cipher.ENCRYPT_MODE, key);
235 final byte[] bytes = crypto.doFinal(data.getBytes());
236 encString = Base64.encodeToString(bytes, Base64.NO_WRAP);
237 } catch (Exception err) {
238 Log.d("KSC", "encrypt key " + err.getMessage());
239 }
240
241 return encString;
242 }
243
244 /**
245 * Wrap AES key.
246 *
247 * @param key Secret Key
248 * @param alias alias for the key
249 * @return Wrapped key
250 */
251 public String wrapKey(final SecretKey key, final String alias) {
252 String localAlias = alias;
253 if (localAlias == null) {
254 localAlias = keyStoreName;
255 }
256 final Cipher crypto;
257 String encodedString = null;
258 try {
259 final KeyPair pair = this.getAsymKeyPair(localAlias);
260
261 crypto = Cipher.getInstance(this.cipherMode);
262 crypto.init(Cipher.WRAP_MODE, pair.getPublic());
263 final byte[] bytes = crypto.wrap(key);
264 encodedString = Base64.encodeToString(bytes, Base64.NO_WRAP);
265 } catch (Exception err) {
266 Log.d("KSC", "wrapKey " + err.getMessage());
267 }
268
269 return encodedString;
270 }
271
272 /**
273 * Unwrap secret key.
274 *
275 * @param key Secret Key
276 * @param alias alias for the key
277 * @return Unwrapped Key
278 */
279 public SecretKey unWrapKey(final String key, final String alias) {
280 String localAlias = alias;
281 if (localAlias == null) {
282 localAlias = keyStoreName;
283 }
284 final Cipher crypto;
285 SecretKey unwrappedKey = null;
286 try {
287 final KeyPair pair = this.getAsymKeyPair(localAlias);
288
289 crypto = Cipher.getInstance(this.cipherMode);
290 crypto.init(Cipher.UNWRAP_MODE, pair.getPrivate());
291 final byte[] encryptedKey = Base64.decode(key, Base64.NO_WRAP);
292 unwrappedKey = (SecretKey) crypto.unwrap(encryptedKey, "AES", Cipher.SECRET_KEY);
293 } catch (Exception err) {
294 Log.d("KSC", "unWrapKey " + err.getMessage());
295 }
296
297 return unwrappedKey;
298 }
299
300 /**
301 * Create a PublicKey from base64 encoded key data.
302 *
303 * @param keyData public Key in string
304 * @return Public key
305 */
306 public PublicKey getPublicKeyFromString(final String keyData) {
307 PublicKey publicKey = null;
308 try {
309 final byte[] keyBytes = Base64.decode(keyData, Base64.DEFAULT);
310 final X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
311 final KeyFactory kf = KeyFactory.getInstance("RSA");
312
313 publicKey = kf.generatePublic(spec);
314 } catch (Exception err) {
315 Log.d("KSC", "getPublicKeyFromString " + err.getMessage());
316 }
317
318 return publicKey;
319 }
320
321 /**
322 * For internal use to see what modes are supported.
323 */
324 public void listProviders() {
325 final Provider[] providers = Security.getProviders();
326 for (Provider provider : providers) {
327 Log.i("KSC", "provider: " + provider.getName());
328 final Set<Provider.Service> services = provider.getServices();
329 for (Provider.Service service : services) {
330 Log.i("KSC", " algorithm: " + service.getAlgorithm());
331 }
332 }
333 }
334
335 /**
336 * Decrypt small amounts of data.
337 *
338 * @param data Data for decryption
339 * @param alias Key alias
340 * @return Decrypted data
341 */
342 public String decrypt(final String data, final String alias) {
343 String localAlias = alias;
344 if (localAlias == null) {
345 localAlias = keyStoreName;
346 }
347 String decryptedString = null;
348 try {
349 final KeyPair pair = this.getAsymKeyPair(localAlias);
350
351 final Cipher crypto = Cipher.getInstance(this.cipherMode);
352 crypto.init(Cipher.DECRYPT_MODE, pair.getPrivate());
353 final byte[] bytes = crypto.doFinal(Base64.decode(data, Base64.NO_WRAP));
354
355 decryptedString = new String(bytes, "UTF-8");
356 } catch (Exception err) {
357 Log.d("KSC", "decrypt string " + err.getMessage());
358 }
359
360 return decryptedString;
361 }
362
363 /**
364 * Decrypt small amounts of data.
365 *
366 * @param data Data for decryption
367 * @param alias Key alias
368 * @return Decrypted data
369 */
370 public byte[] decrypt(final byte[] data, final String alias) {
371 String localAlias = alias;
372 if (localAlias == null) {
373 localAlias = keyStoreName;
374 }
375 byte[] decryptedData = null;
376 try {
377 final KeyPair pair = this.getAsymKeyPair(localAlias);
378
379 final Cipher crypto = Cipher.getInstance(this.cipherMode);
380 crypto.init(Cipher.DECRYPT_MODE, pair.getPrivate());
381 decryptedData = crypto.doFinal(data);
382 } catch (Exception err) {
383 Log.d("KSC", "decrypt byte " + err.getMessage());
384 }
385
386 return decryptedData;
387 }
388}