|
1 /* |
|
2 BEEM is a videoconference application on the Android Platform. |
|
3 |
|
4 Copyright (C) 2009-2012 by Frederic-Charles Barthelery, |
|
5 Nikita Kozlov, |
|
6 Vincent Veronis. |
|
7 |
|
8 This file is part of BEEM. |
|
9 |
|
10 BEEM is free software: you can redistribute it and/or modify |
|
11 it under the terms of the GNU General Public License as published by |
|
12 the Free Software Foundation, either version 3 of the License, or |
|
13 (at your option) any later version. |
|
14 |
|
15 BEEM is distributed in the hope that it will be useful, |
|
16 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
18 GNU General Public License for more details. |
|
19 |
|
20 You should have received a copy of the GNU General Public License |
|
21 along with BEEM. If not, see <http://www.gnu.org/licenses/>. |
|
22 |
|
23 Please send bug reports with examples or suggestions to |
|
24 contact@beem-project.com or http://www.beem-project.com/ |
|
25 |
|
26 */ |
1 package com.beem.project.beem.utils; |
27 package com.beem.project.beem.utils; |
2 |
28 |
3 import android.annotation.TargetApi; |
29 import static com.google.android.apps.iosched.util.LogUtils.LOGD; |
4 import android.os.Build; |
30 import static com.google.android.apps.iosched.util.LogUtils.LOGW; |
5 import android.security.keystore.KeyGenParameterSpec; |
31 import static com.google.android.apps.iosched.util.LogUtils.makeLogTag; |
6 import android.security.keystore.KeyProperties; |
|
7 |
32 |
8 import com.google.android.apps.iosched.util.LogUtils; |
|
9 |
|
10 import org.jivesoftware.smack.util.Base64; |
|
11 |
33 |
12 import java.io.IOException; |
34 import java.io.IOException; |
13 import java.security.GeneralSecurityException; |
35 import java.security.GeneralSecurityException; |
14 import java.security.InvalidAlgorithmParameterException; |
36 import java.security.InvalidAlgorithmParameterException; |
15 import java.security.Key; |
37 import java.security.Key; |
22 import javax.crypto.Cipher; |
44 import javax.crypto.Cipher; |
23 import javax.crypto.KeyGenerator; |
45 import javax.crypto.KeyGenerator; |
24 import javax.crypto.NoSuchPaddingException; |
46 import javax.crypto.NoSuchPaddingException; |
25 import javax.crypto.spec.IvParameterSpec; |
47 import javax.crypto.spec.IvParameterSpec; |
26 |
48 |
27 import static com.google.android.apps.iosched.util.LogUtils.LOGD; |
49 import android.annotation.TargetApi; |
28 import static com.google.android.apps.iosched.util.LogUtils.LOGW; |
50 import android.os.Build; |
|
51 import android.security.keystore.KeyGenParameterSpec; |
|
52 import android.security.keystore.KeyProperties; |
29 |
53 |
|
54 import org.jivesoftware.smack.util.Base64; |
|
55 |
|
56 /** |
|
57 * Allows to encrypt and decrypt some strings using the Android Keystore. |
|
58 */ |
30 public class EncryptionManager { |
59 public class EncryptionManager { |
31 |
60 |
32 private static final String TAG = LogUtils.makeLogTag(EncryptionManager.class); |
61 private static final String TAG = makeLogTag(EncryptionManager.class); |
33 private static final String ANDROID_KEY_STORE = "AndroidKeyStore"; |
62 private static final String ANDROID_KEY_STORE = "AndroidKeyStore"; |
34 private static final String CIPHER_TRANSFORMATION = String.format("%s/%s/%s", |
63 private static final String CIPHER_TRANSFORMATION = String.format("%s/%s/%s", |
35 KeyProperties.KEY_ALGORITHM_AES, KeyProperties.BLOCK_MODE_CBC, |
64 KeyProperties.KEY_ALGORITHM_AES, KeyProperties.BLOCK_MODE_CBC, |
36 KeyProperties.ENCRYPTION_PADDING_PKCS7); |
65 KeyProperties.ENCRYPTION_PADDING_PKCS7); |
37 private boolean isEncryptionAvailable; |
66 private boolean isEncryptionAvailable; |
38 private KeyStore keystore; |
67 private KeyStore keystore; |
39 private KeyGenerator keyGenerator; |
68 private KeyGenerator keyGenerator; |
40 private Cipher aesCipher; |
69 private Cipher aesCipher; |
41 private byte[] latestEncryptionIv; |
70 private byte[] latestEncryptionIv; |
42 |
71 |
|
72 /** |
|
73 * Create an EncryptionManager. |
|
74 */ |
43 public EncryptionManager() { |
75 public EncryptionManager() { |
44 |
|
45 try { |
76 try { |
46 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
77 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
47 keystore = KeyStore.getInstance(ANDROID_KEY_STORE); |
78 keystore = KeyStore.getInstance(ANDROID_KEY_STORE); |
48 keystore.load(null); |
79 keystore.load(null); |
49 aesCipher = Cipher.getInstance(CIPHER_TRANSFORMATION); |
80 aesCipher = Cipher.getInstance(CIPHER_TRANSFORMATION); |
50 keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE); |
81 keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE); |
51 isEncryptionAvailable = true; |
82 isEncryptionAvailable = true; |
52 } else { |
83 } else { |
53 isEncryptionAvailable = false; |
84 isEncryptionAvailable = false; |
54 } |
85 } |
55 } catch (NoSuchPaddingException | KeyStoreException | IOException | NoSuchProviderException | NoSuchAlgorithmException | CertificateException e) { |
86 } catch (NoSuchPaddingException | KeyStoreException | IOException |
|
87 | NoSuchProviderException | NoSuchAlgorithmException | CertificateException e) { |
56 LOGW(TAG, "Unable to load AndroidKeyStore", e); |
88 LOGW(TAG, "Unable to load AndroidKeyStore", e); |
57 isEncryptionAvailable = false; |
89 isEncryptionAvailable = false; |
58 } |
90 } |
59 } |
91 } |
60 |
92 |
|
93 /** |
|
94 * Test if the device supports encryption. |
|
95 * |
|
96 * @return true if encryption is available, false otherwise |
|
97 */ |
61 public boolean isEncryptionAvailable() { |
98 public boolean isEncryptionAvailable() { |
62 return isEncryptionAvailable; |
99 return isEncryptionAvailable; |
63 } |
100 } |
64 |
101 |
|
102 /** |
|
103 * Test if there is an encryption key stored with the alias. |
|
104 * |
|
105 * @param alias the alias to test for |
|
106 * @return true if a key is available, false otherwise |
|
107 */ |
65 public boolean hasEncryptionKey(String alias) { |
108 public boolean hasEncryptionKey(String alias) { |
66 if (!isEncryptionAvailable) { |
109 if (!isEncryptionAvailable) { |
67 return false; |
110 return false; |
68 } |
111 } |
69 try { |
112 try { |
72 LOGD(TAG, "Unable to get key", e); |
115 LOGD(TAG, "Unable to get key", e); |
73 return false; |
116 return false; |
74 } |
117 } |
75 } |
118 } |
76 |
119 |
|
120 /** |
|
121 * Generate a random encryption key and store it in the keystore under alias. |
|
122 * |
|
123 * @param alias the alias use to retrieve the key |
|
124 * @return true if the key was generate, false otherwise |
|
125 */ |
77 @TargetApi(Build.VERSION_CODES.M) |
126 @TargetApi(Build.VERSION_CODES.M) |
78 public boolean generateEncryptionKey(String alias) { |
127 public boolean generateEncryptionKey(String alias) { |
79 if (!isEncryptionAvailable) |
128 if (!isEncryptionAvailable) |
80 return false; |
129 return false; |
81 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) |
130 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(alias, |
82 .setBlockModes(KeyProperties.BLOCK_MODE_CBC) |
131 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) |
83 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) |
132 .setBlockModes(KeyProperties.BLOCK_MODE_CBC) |
84 .setUserAuthenticationRequired(false) |
133 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) |
85 .build(); |
134 .setUserAuthenticationRequired(false) |
86 try { |
135 .build(); |
87 keyGenerator.init(spec); |
136 try { |
88 return keyGenerator.generateKey() != null; |
137 keyGenerator.init(spec); |
89 } catch (InvalidAlgorithmParameterException e) { |
138 return keyGenerator.generateKey() != null; |
90 LOGW(TAG, "Unable to generate key", e); |
139 } catch (InvalidAlgorithmParameterException e) { |
91 return false; |
140 LOGW(TAG, "Unable to generate key", e); |
92 } |
141 return false; |
|
142 } |
93 } |
143 } |
94 |
144 |
|
145 /** |
|
146 * Encrypt a string with the key stored with keyAlias. |
|
147 * |
|
148 * @param cleartext the clear text to encrypt |
|
149 * @param keyAlias the alias of the key to use |
|
150 * @return the encrypted string |
|
151 */ |
95 public String encryptString(String cleartext, String keyAlias) { |
152 public String encryptString(String cleartext, String keyAlias) { |
96 if (!isEncryptionAvailable()) |
153 if (!isEncryptionAvailable()) |
97 return null; |
154 return null; |
98 try { |
155 try { |
99 Key key = keystore.getKey(keyAlias, null); |
156 Key key = keystore.getKey(keyAlias, null); |
105 LOGW(TAG, "Unable to encrypt text", e); |
162 LOGW(TAG, "Unable to encrypt text", e); |
106 return null; |
163 return null; |
107 } |
164 } |
108 } |
165 } |
109 |
166 |
|
167 /** |
|
168 * Get the encryption IV used with the latest encryption operation. |
|
169 * |
|
170 * @return the encryption IV or null if no encryption operation has been done |
|
171 */ |
110 public byte[] getLatestEncryptionIv() { |
172 public byte[] getLatestEncryptionIv() { |
111 return latestEncryptionIv; |
173 return latestEncryptionIv; |
112 } |
174 } |
113 |
175 |
114 public String decryptString(String password, String keyAlias, byte[] encryptionIv) { |
176 /** |
|
177 * Decrypt an encrypted text using the key stored with alias keyAlias and the specified encryption IV. |
|
178 * |
|
179 * @param encryptedText the encrypted text to decrypt |
|
180 * @param keyAlias the alias of the key to use |
|
181 * @param encryptionIv the encryption IV |
|
182 * @return the clear text |
|
183 */ |
|
184 public String decryptString(String encryptedText, String keyAlias, byte[] encryptionIv) { |
115 if (!isEncryptionAvailable()) |
185 if (!isEncryptionAvailable()) |
116 return null; |
186 return null; |
117 try { |
187 try { |
118 Key key = keystore.getKey(keyAlias, null); |
188 Key key = keystore.getKey(keyAlias, null); |
119 byte[] passwordByte = Base64.decode(password); |
189 byte[] passwordByte = Base64.decode(encryptedText); |
120 aesCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(encryptionIv)); |
190 aesCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(encryptionIv)); |
121 byte[] clear = aesCipher.doFinal(passwordByte); |
191 byte[] clear = aesCipher.doFinal(passwordByte); |
122 return new String(clear); |
192 return new String(clear); |
123 } catch (GeneralSecurityException e) { |
193 } catch (GeneralSecurityException e) { |
124 LOGW(TAG, "Unable to decrypt text", e); |
194 LOGW(TAG, "Unable to decrypt text", e); |