2016-06-20 14 views
0

テキストフィールドを安全に保存しようとしています。そのために、私はコンテンツを暗号化し解読しようとしています。これはコードです:Androidでテキストを暗号化するときに復号化で空の文字列が返される

public class SecureStorage { 

    public String getPassword() { 
     if(!isRooted()) { 
      String password = pref.getPassword(""); 
      System.out.println("pass getPass: " + password); 
      return password.isEmpty() ? password : new String(decrypt(Base64.decode(password, Base64.DEFAULT))); 

     } else 
      return ""; 
    } 

    public void setPassword(String passwordStr) { 
     if(!isRooted()) { 
      byte[] password = encrypt(passwordStr.getBytes()); 
      pref.setPassword(password == null ? "" : Base64.encodeToString(password, Base64.DEFAULT)); 
     } 
    } 

    private SecretKey generateKey() { 
     // Generate a 256-bit key 
     final int outputKeyLength = 256; 
     try { 
      SecureRandom secureRandom = new SecureRandom(); 
      // Do *not* seed secureRandom! Automatically seeded from system entropy. 
      KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); 
      keyGenerator.init(outputKeyLength, secureRandom); 
      return keyGenerator.generateKey(); 
     } catch (NoSuchAlgorithmException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    private byte[] getRawKey(byte[] key) throws Exception { 
     KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); 
     SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG", "Crypto"); 
     secureRandom.setSeed(key); 
     keyGenerator.init(128, secureRandom); // 192 and 256 bits may not be available 
     SecretKey secretKey = keyGenerator.generateKey(); 
     byte[] rawKey = secretKey.getEncoded(); 
     return rawKey; 
    } 

    /** The method that encrypts the string. 
    @param toEncrypt The string to be encrypted. 
    @return The encrypted string in bytes. */ 
    //**************************************** 
    private byte[] encrypt(byte[] toEncrypt) { 
     byte[] encryptedByte = new String().getBytes(); 
     try { 
      SecretKeySpec secretKeySpec = new SecretKeySpec(getRawKey(Utils.generateUID().getBytes()), "AES"); 
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); 
      encryptedByte = cipher.doFinal(toEncrypt); 
     } catch (NoSuchAlgorithmException e) { 
      e.printStackTrace(); 
     } catch (InvalidKeyException e) { 
      e.printStackTrace(); 
     } catch (NoSuchPaddingException e) { 
      e.printStackTrace(); 
     } catch (BadPaddingException e) { 
      e.printStackTrace(); 
     } catch (IllegalBlockSizeException e) { 
      e.printStackTrace(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     return encryptedByte; 
    } 

    //************************************** 
    /** The method that decrypts the string. 
    @param encryptedByte The string to be encrypted. 
    @return The decrypted string in bytes. */ 
    //**************************************** 
    private byte[] decrypt(byte[] encryptedByte) { 
     byte[] decryptedByte = new String().getBytes(); 
     try { 
      SecretKeySpec secretKeySpec = new SecretKeySpec(getRawKey(Utils.generateUID().getBytes()), "AES"); 
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); 
      decryptedByte = cipher.doFinal(encryptedByte); 
     } catch (NoSuchAlgorithmException e) { 
      e.printStackTrace(); 
     } catch (InvalidKeyException e) { 
      e.printStackTrace(); 
     } catch (NoSuchPaddingException e) { 
      e.printStackTrace(); 
     } catch (BadPaddingException e) { 
      e.printStackTrace(); 
     } catch (IllegalBlockSizeException e) { 
      e.printStackTrace(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     return decryptedByte; 
    } 
} 

私はテキストを暗号化できます。 私はSharedPreferencesを使用して暗号化されたテキストを保存し、sharedprefsを取得してテキストを復号化してTextViewに渡します。しかし、getPassword()では、SharedPreference値を取得していて、SharedPrefsに値があれば復号化しようとしています。私はSharedPrefsを文字列(password)にして、それを解読しようとしていますが、私はできません!私は空の文字列を取得しています!

+0

'pref.getPassword(" ");'は何ですか? – Jimmy

+0

可能なすべての例外をキャッチしているため、空の文字列が表示されています。どの例外がスローされたかを調べるためにログを調べましたか?私はそれがBadPaddingExceptionだと思う –

+0

それを得た!, Im世代ランダムキーとそれを保存していない!だから、今私は新しい鍵を呼び戻すとき。今では、テキストと一緒にキーを保存しています! –

答えて

1

CBCモードでは、動作するために初期化ベクトル(IV)が必要です。 IVは、暗号文をランダム化し、攻撃者が以前の平文が現在のプレインテキストと同じプレフィックスを持つかどうかを判断するのを防ぎます。

IVを生成していないので、生成されます。誤ったIVは、最初のブロック(AESの最初の16バイト)にのみ影響します。プレーンテキストがブロックよりも短い場合、完全に異なる解読につながり、パディングはおよそ255/256の確率で削除できません。

IVは秘密ではありません。それを暗号文の前に置いて、解読する前にスライスしておくのが一般的です。

public byte[] encrypt(byte[] toEncrypt) throws Exception { 
    try { 
     SecretKeySpec secretKeySpec = new SecretKeySpec(getRawKey(Utils.generateUID().getBytes()), "AES"); 
     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); 
     byte[] iv = cipher.getIV(); 
     byte[] ct = cipher.doFinal(toEncrypt); 

     byte[] result = new byte[ct.length + iv.length]; 
     System.arraycopy(iv, 0, result, 0, iv.length); 
     System.arraycopy(ct, 0, result, iv.length, ct.length); 
     return result; 
    } catch(...) {...} 
    return new byte[0]; 
} 

public byte[] decrypt(byte[] encryptedByte) throws Exception { 
    try { 
     SecretKeySpec secretKeySpec = new SecretKeySpec(getRawKey(Utils.generateUID().getBytes()), "AES"); 
     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 

     byte[] iv = new byte[cipher.getBlockSize()]; 
     byte[] ct = new byte[encryptedByte.length - cipher.getBlockSize()]; 
     System.arraycopy(encryptedByte, 0, iv, 0, cipher.getBlockSize()); 
     System.arraycopy(encryptedByte, cipher.getBlockSize(), ct, 0, ct.length); 

     cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(iv)); 
     return cipher.doFinal(ct); 
    } catch (...) {...} 
    return new byte[0]; 
} 

この問題は、暗号文が予想よりも大きかった可能性があります(IVの場合は16バイト追加)。攻撃者が前のプレーンテキストの接頭辞が同じであると判断して有用な情報が得られない場合は、静的なIVを使用できます。しかし、これは通常考えの偉大さではないことをご承知おきください。が本当にそのスペースをにする必要がある場合にのみ行うべきです。

private static final byte[] IV = new byte[16]; 
... 
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(IV)); 
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(IV)); 
関連する問題