Back to project page PasswordDroid.
The source code is released under:
GNU General Public License
If you think the Android project PasswordDroid listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package de.wuthoehle.passworddroid.crypto; /*from ww w. j av a 2s .c o m*/ /* Copyright (c) 2015 Marco Huenseler <marcoh.huenseler+git@gmail.com> * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import java.nio.ByteBuffer; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.util.LinkedList; import java.util.Queue; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.SecretKeySpec; public class AESprng { // This class uses AES-256 in CTR mode to act as a CSPRNG // Be sure to know how CTR mode works before using it private byte[] nonce; private long counter; private Cipher generator; private Queue<Byte> random_bytes; public AESprng(byte[] key, byte[] nonce) throws GeneralSecurityException { if (key.length != 32 || nonce.length != 8) { throw new IllegalArgumentException("CSPRNG: Need 256bit key and 64bit nonce."); } this.nonce = nonce; this.counter = 0; this.random_bytes = new LinkedList<>(); try { // Get AES instance and set 256-bit key this.generator = Cipher.getInstance("AES/ECB/NoPadding", "BC"); this.generator.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES")); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); throw new GeneralSecurityException("AESprng is unable to operate: NoSuchAlgorithm"); } catch (NoSuchProviderException e) { e.printStackTrace(); throw new GeneralSecurityException("AESprng is unable to operate: NoSuchProvider"); } catch (NoSuchPaddingException e) { e.printStackTrace(); throw new GeneralSecurityException("AESprng is unable to operate: NoSuchPadding"); } } public static int bitsForRange(int len) { return (int) Math.ceil(Math.log(len) / Math.log(2.0)); } public int getInteger(int bits) throws GeneralSecurityException { if (bits > Integer.SIZE) { throw new IllegalArgumentException("AESprng: Integer can only be " + Integer.SIZE + "bits long"); } byte[] bytes; bytes = getRandom((int) Math.ceil((double) bits / 8)); int result = 0; for (int i = 0; i < bytes.length; i++) { result |= ((int) bytes[i] & 0xFF) << (Integer.SIZE - ((i + 1) * 8)); } result >>>= Integer.SIZE - bits; return result; } public int getInteger() throws GeneralSecurityException { return getInteger(Integer.SIZE); } public byte[] getRandom(int size) throws GeneralSecurityException { byte[] result = new byte[size]; for (int i = 0; i < size; i++) { if (random_bytes.size() == 0) { needMoreRandom(); } result[i] = random_bytes.remove(); } return result; } private void needMoreRandom() throws GeneralSecurityException { if (random_bytes.size() == 0) { // Plaintext block is now <8 Byte nonce><8 Byte counter> // Counter gets incremented after seccessfully producing a ciphertext block byte[] plain_block = ByteBuffer.allocate(16).put(this.nonce).putLong(this.counter).array(); try { byte[] cipher_block = this.generator.doFinal(plain_block); for (byte i : cipher_block) { this.random_bytes.add(i); } } catch (IllegalBlockSizeException e) { e.printStackTrace(); throw new GeneralSecurityException("AESprng is unable to operate: IllegalBlockSize"); } catch (BadPaddingException e) { throw new GeneralSecurityException("AESprng is unable to operate: BadPadding"); } counter++; } } }