-
Notifications
You must be signed in to change notification settings - Fork 56
/
KeyStoreKeyGenerator.java
94 lines (77 loc) · 3.06 KB
/
KeyStoreKeyGenerator.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package in.co.ophio.secure.core;
import android.app.Application;
import android.security.KeyChain;
import android.util.Base64;
import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import in.co.ophio.secure.vault.SecretKeyWrapper;
import in.co.ophio.secure.vault.Utils;
/**
* @author Gaurav Vashisth (vashisthg@gmail.com)
*/
public class KeyStoreKeyGenerator implements KeyGenerator {
public static final String TAG = "KeyGenerator";
private static final int DATA_KEY_LENGTH = 32;
private Application application;
/**
* Flag indicating that the {@link SecretKeyWrapper} public/private key is
* hardware-backed. A software keystore is more vulnerable to offline
* attacks if the device is compromised.
*/
private boolean isHardwareBacked;
/** File where wrapped symmetric key is stored. */
private File keyFile;
private KeyStoreKeyGenerator(Application application, String filename) {
this.application = application;
this.isHardwareBacked = KeyChain.isBoundKeyAlgorithm("RSA");
this.keyFile = new File(application.getFilesDir(), filename);
try {
// Load secret key and ensure our root document is ready.
loadOrGenerateKeys();
} catch (IOException e) {
throw new IllegalStateException(e);
} catch (GeneralSecurityException e) {
throw new IllegalStateException(e);
}
}
public static KeyStoreKeyGenerator get(Application application, String fileName) {
return new KeyStoreKeyGenerator(application, fileName);
}
/**
* If key is already present then returns it otherwise generates a random key and returns it
* @return key
*/
@Override
public String loadOrGenerateKeys()
throws GeneralSecurityException, IOException {
final SecretKeyWrapper wrapper = new SecretKeyWrapper(application, TAG);
// Generate secret key if none exists
if (!keyFile.exists()) {
final byte[] raw = new byte[DATA_KEY_LENGTH];
new SecureRandom().nextBytes(raw);
final SecretKey key = new SecretKeySpec(raw, "AES");
final byte[] wrapped = wrapper.wrap(key);
Utils.writeFully(keyFile, wrapped);
}
// Even if we just generated the key, always read it back to ensure we
// can read it successfully.
final byte[] wrapped = Utils.readFully(keyFile);
final SecretKey key = wrapper.unwrap(wrapped);
return Base64.encodeToString(key.getEncoded(), Base64
.DEFAULT);
}
/**
* Indicates whether the {@link SecretKeyWrapper} public/private key is
* hardware-backed. A software keystore is more vulnerable to offline
* attacks if the device is compromised.
* @return boolean to know wheter key is hardware backed or not
*/
@Override
public boolean isHardwareBacked() {
return isHardwareBacked;
}
}