app/src/main/java/com/beem/project/beem/utils/EncryptionManager.java
changeset 1076 137d0bf0e959
parent 1074 fde61b09cd8d
equal deleted inserted replaced
1075:af8866eba015 1076:137d0bf0e959
       
     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);