/*
* *
* Copyright (C) 2014 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* /
*/
package org.anhonesteffort.flock.crypto;
import android.util.Log;
import org.anhonesteffort.flock.util.Base64;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
/**
* Programmer: rhodey
*/
public class KeyUtil {
private static final String TAG = "org.anhonesteffort.flock.crypto.KeyUtil";
protected static final int CIPHER_KEY_LENGTH_BYTES = 32;
protected static final int MAC_KEY_LENGTH_BYTES = 32;
protected static final int SALT_LENGTH_BYTES = 8;
private static final int ITERATION_COUNT_AUTH_TOKEN = 20050;
private static final int ITERATION_COUNT_KEY_MATERIAL = 20000;
protected static byte[] generateCipherKey() throws NoSuchAlgorithmException {
Log.d(TAG, "generateCipherKey()");
byte[] cipherKey = new byte[CIPHER_KEY_LENGTH_BYTES];
SecureRandom.getInstance("SHA1PRNG").nextBytes(cipherKey);
return cipherKey;
}
protected static byte[] generateMacKey() throws NoSuchAlgorithmException {
Log.d(TAG, "generateMacKey()");
byte[] macKey = new byte[MAC_KEY_LENGTH_BYTES];
SecureRandom.getInstance("SHA1PRNG").nextBytes(macKey);
return macKey;
}
protected static byte[] generateSalt() throws NoSuchAlgorithmException {
Log.d(TAG, "generateSalt()");
byte[] salt = new byte[SALT_LENGTH_BYTES];
SecureRandom.getInstance("SHA1PRNG").nextBytes(salt);
return salt;
}
public static String getAuthTokenForPassphrase(String passphrase)
throws GeneralSecurityException
{
byte[] salt = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
SecretKey authKey = getKeyForPassphrase(passphrase, salt, ITERATION_COUNT_AUTH_TOKEN);
return Base64.encodeBytes(authKey.getEncoded());
}
protected static SecretKey[] getCipherAndMacKeysForPassphrase(byte[] salt, String passphrase)
throws GeneralSecurityException
{
SecretKey combinedKeys = getKeyForPassphrase(passphrase, salt, ITERATION_COUNT_KEY_MATERIAL);
byte[] cipherKeyBytes = Arrays.copyOfRange(combinedKeys.getEncoded(), 0, CIPHER_KEY_LENGTH_BYTES);
byte[] macKeyBytes = Arrays.copyOfRange(combinedKeys.getEncoded(),
CIPHER_KEY_LENGTH_BYTES,
CIPHER_KEY_LENGTH_BYTES + MAC_KEY_LENGTH_BYTES);
SecretKey cipherKey = new SecretKeySpec(cipherKeyBytes, combinedKeys.getAlgorithm());
SecretKey macKey = new SecretKeySpec(macKeyBytes, combinedKeys.getAlgorithm());
return new SecretKey[] {cipherKey, macKey};
}
private static SecretKey getKeyForPassphrase(String passphrase, byte[] salt, int iterationCount)
throws GeneralSecurityException
{
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec keySpec = new PBEKeySpec(passphrase.toCharArray(), salt, iterationCount, (64 * 8));
return keyFactory.generateSecret(keySpec);
}
}