(FRONT) FRONT (2025)

Return to Cryptographic service CryptoStorageService

   1:  package com.voipplus.mmsclient.serviceLocalStorage;
   2:  
   3:  import android.app.Service;
   4:  import android.content.Intent;
   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 intent) {
  92:          return binder;
  93:      }
  94:  
  95:      @Override
  96:      public int onStartCommand(Intent 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:



Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23>  <24>  <25
Link to this page: http://www.vb-net.com/AndroidMosaic/CryptoStorageService.htm
<TAGS>  <ARTICLES>  <FRONT>  <CORE>  <MVC>  <ASP>  <NET>  <DATA>  <TASK>  <XML>  <KIOSK>  <NOTES>  <SQL>  <LINUX>  <MONO>  <FREEWARE>  <DOCS> <TRAVELS> <FLOWERS> <RESUME> < THANKS ME>