Return to Cryptographic service CryptoStorageService
1: package com.voipplus.mmsclient.serviceLocalStorage;
2:
3: import android.app.Service;
4: import android.content. ;
5: import android.os.Binder;
6: import android.os.IBinder;
7: import android.security.keystore.KeyGenParameterSpec;
8: import android.security.keystore.KeyProperties;
9: import android.util.Base64;
10: import android.util.Log;
11: import android.util.Pair;
12:
13: import androidx.annotation.Nullable;
14:
15: import java.io.IOException;
16: import java.nio.charset.StandardCharsets;
17: import java.security.InvalidAlgorithmParameterException;
18: import java.security.InvalidKeyException;
19: import java.security.Key;
20: import java.security.KeyStore;
21: import java.security.NoSuchAlgorithmException;
22: import java.security.NoSuchProviderException;
23: import java.security.SecureRandom;
24: import java.security.UnrecoverableKeyException;
25: import java.security.cert.CertificateException;
26: import java.util.Arrays;
27: import java.util.HashMap;
28: import java.util.Map;
29: import java.util.Set;
30:
31: import javax.crypto.BadPaddingException;
32: import javax.crypto.Cipher;
33: import javax.crypto.IllegalBlockSizeException;
34: import javax.crypto.KeyGenerator;
35: import javax.crypto.NoSuchPaddingException;
36: import javax.crypto.SecretKey;
37: import javax.crypto.spec.GCMParameterSpec;
38: import javax.crypto.spec.SecretKeySpec;
39:
40: public class CryptoStorageService extends Service {
41:
42: private static final String TAG = "CryptoStorageService";
43: private final KeyStore keyStore;
44: private final String keyAlias = "MyKeyAlias";
45: private final String transformation = "AES/GCM/NoPadding";
46: private final int ivLength = 12; // GCM standard is 12 bytes
47: private final int gcmTagLength = 128;
48: private final Map<String, String> storage;
49:
50: public class LocalBinder extends Binder {
51: public CryptoStorageService getService() {
52: return CryptoStorageService.this;
53: }
54: }
55:
56: private final IBinder binder = new LocalBinder();
57:
58: public CryptoStorageService() {
59: try {
60: keyStore = KeyStore.getInstance("AndroidKeyStore");
61: keyStore.load(null);
62: storage = new HashMap<>();
63: } catch (java.security.KeyStoreException e) {
64: Log.e(TAG, "Error initializing CryptoStorageService", e);
65: throw new RuntimeException(e); // Re-throw to prevent service from starting
66: } catch (CertificateException e) {
67: Log.e(TAG, "Error initializing CryptoStorageService", e);
68: throw new RuntimeException(e); // Re-throw to prevent service from starting
69: } catch (IOException e) {
70: Log.e(TAG, "Error initializing CryptoStorageService", e);
71: throw new RuntimeException(e); // Re-throw to prevent service from starting
72: } catch (NoSuchAlgorithmException e) {
73: Log.e(TAG, "Error initializing CryptoStorageService", e);
74: throw new RuntimeException(e); // Re-throw to prevent service from starting
75: }
76: }
77:
78: @Override
79: public void onCreate() {
80: super.onCreate();
81: try {
82: keyStore.load(null);
83: } catch (CertificateException | IOException | NoSuchAlgorithmException e) {
84: Log.e(TAG, "Error loading KeyStore in onCreate", e);
85: throw new RuntimeException(e); // Re-throw to prevent service from starting
86: }
87: }
88:
89: @Nullable
90: @Override
91: public IBinder onBind( intent) {
92: return binder;
93: }
94:
95: @Override
96: public int onStartCommand( intent, int flags, int startId) {
97: // Do your work here
98: return START_STICKY;
99: }
100:
101: public void put(String key, String value) {
102: try {
103: SecretKey dataKey = generateDataKey();
104: Pair<byte[], byte[]> encryptionResult = encryptData(value.getBytes(StandardCharsets.UTF_8), dataKey);
105: byte[] encryptedData = encryptionResult.first;
106: byte[] iv= encryptionResult.second;
107: Pair<byte[], byte[]> encryptedDataKeyAndIv = encryptDataKey(dataKey);
108: byte[] encryptedDataKey = encryptedDataKeyAndIv.first;
109: byte[] ivDataKey = encryptedDataKeyAndIv.second;
110: byte[] combined = new byte[iv.length + encryptedData.length];
111: System.arraycopy(iv, 0, combined, 0, iv.length);
112: System.arraycopy(encryptedData, 0, combined, iv.length, encryptedData.length);
113: String encryptedValue = Base64.encodeToString(combined, Base64.DEFAULT);
114: byte[] combinedDataKey = new byte[ivDataKey.length + encryptedDataKey.length];
115: System.arraycopy(ivDataKey, 0, combinedDataKey, 0, ivDataKey.length);
116: System.arraycopy(encryptedDataKey, 0, combinedDataKey, ivDataKey.length, encryptedDataKey.length);
117: String encryptedDataKeyString = Base64.encodeToString(combinedDataKey, Base64.DEFAULT);
118: storage.put(key, encryptedValue + "|" + encryptedDataKeyString);
119: } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeyException |
120: InvalidAlgorithmParameterException | java.security.KeyStoreException |
121: UnrecoverableKeyException | IllegalBlockSizeException | BadPaddingException |
122: NoSuchPaddingException e) {
123: Log.e(TAG, "Error encrypting data", e);
124: }
125: }
126: public String get(String key) {
127: String encryptedValueAndDataKey = storage.get(key);
128: if (encryptedValueAndDataKey == null) {
129: return null;
130: }
131: try {
132: String[] parts = encryptedValueAndDataKey.split("\|");
133: String encryptedValueWithIv = parts[0];
134: String encryptedDataKeyString = parts[1];
135: byte[] combined = Base64.decode(encryptedValueWithIv, Base64.DEFAULT);
136: byte[] iv = Arrays.copyOfRange(combined,0, ivLength);
137: byte[] encryptedData = Arrays.copyOfRange(combined, ivLength, combined.length);
138: byte[] combinedDataKey = Base64.decode(encryptedDataKeyString, Base64.DEFAULT);
139: byte[] ivDataKey = Arrays.copyOfRange(combinedDataKey, 0, ivLength);
140: byte[] encryptedDataKey = Arrays.copyOfRange(combinedDataKey, ivLength, combinedDataKey.length);
141: SecretKey dataKey = decryptDataKey(encryptedDataKey, ivDataKey);
142: byte[] decryptedBytes = decryptData(encryptedData, iv, dataKey);
143: return new String(decryptedBytes, StandardCharsets.UTF_8);
144: } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeyException |
145: InvalidAlgorithmParameterException | java.security.KeyStoreException |
146: UnrecoverableKeyException | IllegalBlockSizeException | BadPaddingException |
147: NoSuchPaddingException e) {
148: Log.e(TAG, "Error decrypting data", e);
149: return null;
150: }
151: }
152:
153: public void remove(String key) {
154: storage.remove(key);}
155:
156: public boolean contains(String key) {
157: return storage.containsKey(key);
158: }
159:
160: public Set<String> list() {
161: return storage.keySet();
162: }
163:
164: private SecretKey generateDataKey() throws NoSuchAlgorithmException {
165: KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
166: keyGenerator.init(256);
167: return keyGenerator.generateKey();
168: }
169:
170: private Pair<byte[], byte[]> encryptDataKey(SecretKey dataKey) throws NoSuchAlgorithmException, InvalidKeyException,
171: NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnrecoverableKeyException, java.security.KeyStoreException, InvalidAlgorithmParameterException, NoSuchProviderException {
172: Key masterKey = getOrCreateKey();
173: Cipher cipher = Cipher.getInstance(transformation);
174: cipher.init(Cipher.ENCRYPT_MODE, masterKey);
175: byte[] encryptedDataKey = cipher.doFinal(dataKey.getEncoded());
176: byte[] iv = cipher.getIV();
177: return new Pair<>(encryptedDataKey, iv);
178: }
179:
180: private SecretKey decryptDataKey(byte[] encryptedDataKey, byte[] iv) throws NoSuchAlgorithmException, InvalidKeyException,
181: NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnrecoverableKeyException, java.security.KeyStoreException, InvalidAlgorithmParameterException, NoSuchProviderException {
182: Key masterKey = getOrCreateKey();
183: Cipher cipher = Cipher.getInstance(transformation);
184: GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(gcmTagLength, iv);
185: cipher.init(Cipher.DECRYPT_MODE, masterKey, gcmParameterSpec);
186: byte[] decryptedDataKey = cipher.doFinal(encryptedDataKey);
187: return new SecretKeySpec(decryptedDataKey, KeyProperties.KEY_ALGORITHM_AES);
188: }
189:
190: private Pair<byte[], byte[]> encryptData(byte[] data, SecretKey dataKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, java.security.KeyStoreException, UnrecoverableKeyException, NoSuchProviderException {
191: Cipher cipher = Cipher.getInstance(transformation);
192: // Generate a random IV
193: byte[] iv= new byte[ivLength];
194: SecureRandom secureRandom = new SecureRandom();
195: secureRandom.nextBytes(iv);
196: // Initialize the cipher for encryption with the key and IV
197: GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(gcmTagLength, iv);
198: cipher.init(Cipher.ENCRYPT_MODE, dataKey, gcmParameterSpec);
199:
200: // Encrypt the data
201: byte[] encryptedData = cipher.doFinal(data);
202:
203: // Return the encrypted data and the IV
204: return new Pair<>(encryptedData, iv);
205: }
206:
207: private byte[] decryptData(byte[] encryptedData, byte[] iv, SecretKey dataKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, java.security.KeyStoreException, UnrecoverableKeyException, NoSuchProviderException {
208: Cipher cipher = Cipher.getInstance(transformation);
209: // Create an GCMParameterSpec from the stored IV
210: GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(gcmTagLength, iv);
211:
212: // Initialize the cipher for decryption with the key and IV
213: cipher.init(Cipher.DECRYPT_MODE, dataKey, gcmParameterSpec);
214:
215: // Decrypt the data
216: return cipher.doFinal(encryptedData);
217: }
218:
219: private Key getOrCreateKey() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, java.security.KeyStoreException, UnrecoverableKeyException, NoSuchProviderException {
220: if (keyStore.containsAlias(keyAlias)) {
221: return keyStore.getKey(keyAlias, null);
222: } else {
223: KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
224: KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(keyAlias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
225: .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
226: .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
227: .setKeySize(256)
228: .build();
229: keyGenerator.init(keyGenParameterSpec);
230: return keyGenerator.generateKey();
231: }}
232: }
233:
Return to Cryptographic service
AndroidMosaic context:
- 2025 year: Resolve class conflicts #AndroidMosaic
- 2025 year: Application level parameters in configuration #AndroidMosaic
- 2025 year: Create test with junit and pass or dismiss test before application launch #AndroidMosaic
- 2025 year: Ask special permission and listen answer #AndroidMosaic
- 2025 year: Service lifecycle #AndroidMosaic
- 2025 year: AtomicInteger and accept service callback in UI thread, stop progressBar that was run in UiThread #AndroidMosaic
- 2025 year: Generate random data and pass it to RecyclerView with Adapter #AndroidMosaic
- 2025 year: Pass data to new form with Intent and getParcelableExtra #AndroidMosaic
- 2025 year: Access to Contact list #AndroidMosaic
- 2025 year: Using Query and Cursor to read data sequence and fill DataAdapter for RecyclerView #AndroidMosaic
- 2025 year: Custom TabSwithcer #AndroidMosaic
- 2025 year: Custom Dropdownlist with default value based on Spinner #AndroidMosaic
- 2025 year: Create MMS service and route MMS to Emulator #AndroidMosaic
- 2025 year: Vector drawable - fastest way to create icons #AndroidMosaic
- 2025 year: Technique to create Button with own rectangle shape #AndroidMosaic
- 2025 year: Simple HTTP service #AndroidMosaic
- 2025 year: Simple key-value service with Local Storage #AndroidMosaic
- 2025 year: Cryptographic local storage key-value service #AndroidMosaic
- 2025 year: WebRTC service #AndroidMosaic
- 2025 year: SIP service #AndroidMosaic
- 2025 year: Global objects with references to all application services #AndroidMosaic
Comments (
)

Link to this page:
http://www.vb-net.com/AndroidMosaic/CryptoStorageService.htm
|