LoginSignup
15
20

More than 5 years have passed since last update.

アプリ内に保存するデータを暗号化する(Android)

Last updated at Posted at 2017-12-22

最初に...

初投稿です。
普段アプリ開発をする際に、IDなどをアプリ内に保存した際、いつも平文でした。
アプリ内に保存はしていますが、念のため暗号化しようと思い
AES暗号鍵を使用して値を暗号化して保存してみましたので、それについての記事となります。
まず、AES採用の理由とAndroidにおける鍵の保存領域について。

AES(Advanced Encryption Standard)

AESにした理由は、CRYPTRECにて共通鍵暗号にて推奨されているためです。
(参考:http://www.cryptrec.go.jp/list/cryptrec-ls-0001-2016.pdf)
また、RSAにしない理由としては鍵の使用者が一人しかいないので
非対称鍵にする必要がないと思いました。

AndroidKeyStoreSystem? :thinking:

AndroidOSが提供している鍵をセキュアに保存できる領域です。
(APKで使うKeyStoreじゃないです。)
ちなみに指紋認証付き端末ですと、鍵を使用する際に指紋認証をすることを
条件にすることもでき更にセキュアになります。
(Androidの指紋認証付き端末のシェア率を考慮すると、微妙なので
採用は見送りました)

実際のソース

AES鍵作成

public void createAESKey() {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,"AndroidKeyStore");
            keyGenerator.init(new KeyGenParameterSpec.Builder(ALIAS,KeyProperties.PURPOSE_ENCRYPT|KeyProperties.PURPOSE_DECRYPT)//この鍵は、暗号化・復号を目的として作成しますということを明示してます
            .setCertificateSubject(new X500Principal("CN="+ALIAS))
            .setCertificateSerialNumber(BigInteger.ONE)
            .setBlockModes(KeyProperties.BLOCK_MODE_CBC)//CBC=「Cipher Block Chaining mode」
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
            .setRandomizedEncryptionRequired(false)//初期化ベクトルを固定値とする設定をしています。
            .build());
            keyGenerator.generateKey();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
    }

暗号化

public String encrypt(String text) {
        try {
            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);
            if (!keyStore.containsAlias(ALIAS)) {
                createAESKey();
            }
            SecretKey secretKey = (SecretKey)keyStore.getKey(ALIAS,null);

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            IvParameterSpec ivParameterSpec = new IvParameterSpec(IVKEY.getBytes());
            cipher.init(Cipher.ENCRYPT_MODE,secretKey,ivParameterSpec);

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream,cipher);
            cipherOutputStream.write(text.getBytes("UTF-8"));
            cipherOutputStream.close();
            return Base64.encodeToString(outputStream.toByteArray(),Base64.NO_WRAP);
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return null;
    }

復号

public String decrypt(String encryptText) {
        try {
            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);
            SecretKey secretKey = (SecretKey)keyStore.getKey(ALIAS,null);

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            IvParameterSpec ivParameterSpec = new IvParameterSpec(IVKEY.getBytes());
            cipher.init(Cipher.DECRYPT_MODE,secretKey,ivParameterSpec);

            CipherInputStream cipherInputStream = new CipherInputStream(new ByteArrayInputStream(Base64.decode(encryptText,Base64.NO_WRAP)),cipher);
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            int buffer;
            while ((buffer = cipherInputStream.read())!= -1) {
                byteArrayOutputStream.write(buffer);
            }
            byteArrayOutputStream.close();
            return byteArrayOutputStream.toString("UTF-8");
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return null;
    }

呼び出し

KeyService keyService = new KeyService();
keyService.createAESKey();
String text = "5000兆円欲しい";
String encryptText = keyService.encrypt(text);
String text2 = keyService.decrypt(encryptText);
Log.d("","text="+text);
Log.d("","encryptText="+encryptText);
Log.d("","text2="+text2);

結果

text=5000兆円欲しい
encryptText=ooIvV63AJIyyRhZUpUJ2Le4B2DyWUw1ZmSG33Z2IhQM=
text2=5000兆円欲しい

最後に

ご覧いただき、ありがとうございます。
次回はSwift4で同じことをする予定です・・・。

15
20
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
20