Provides symmetric key cryptography and hashing.
/*
* Copyright 2010 Pedro Fonseca
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//package com.hecticant.thinpass.security;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import android.util.Log;
/**
* Provides symmetric key cryptography and hashing.
*
* @author Pedro Fonseca
*/
public class CryptUtil {
private static final String TAG = "CryptUtil";
private static final int KEYSIZE = 128;
private static SecureRandom rd;
static {
try {
rd = SecureRandom.getInstance("SHA1PRNG");
}
catch (NoSuchAlgorithmException e) {
Log.e(TAG, e.getLocalizedMessage());
throw new RuntimeException("Certainly a random error", e);
}
}
private static final byte[] defaultIV = { 127, 24, 123, 23, 93, 7, 15, 0,
9, 4, 8, 15, 16, 23, 42, 1};
public static SecretKey genMasterKey(char[] pwd, byte[] salt) {
SecretKeyFactory kf;
PBEKeySpec ks;
SecretKey sk;
try {
// Android does not support PBKDF2WithHmacSHA1 but BouncyCastle
// is included. For a bit of archaeology see
// http://www.google.com/codesearch/p?hl=en#atE6BTe41-M
// /libcore/security/src/main/java/org/bouncycastle/jce
// /provider/BouncyCastleProvider.java
kf = SecretKeyFactory.getInstance("PBEWITHSHAAND128BITAES-CBC-BC");
ks = new PBEKeySpec(pwd, salt, 1000, KEYSIZE);
sk = kf.generateSecret(ks);
ks.clearPassword();
}
catch (GeneralSecurityException e) {
Log.e(TAG, e.getLocalizedMessage());
throw new IllegalStateException("Error generating secret key", e);
}
return sk;
}
public static SecretKey genRandomKey() {
KeyGenerator kg;
try {
kg = KeyGenerator.getInstance("AES");
kg.init(KEYSIZE, rd);
} catch (GeneralSecurityException e) {
Log.e(TAG, e.getLocalizedMessage());
throw new IllegalStateException("Error generating secret key", e);
}
return kg.generateKey();
}
public static byte[] encrypt(byte[] key, byte[] clearText) {
return encrypt(keyFromBytes(key), clearText);
}
public static byte[] decrypt(byte[] key, byte[] encryptedText) {
return decrypt(keyFromBytes(key), encryptedText);
}
public static byte[] encrypt(SecretKey key, byte[] clearText) {
return transform(Cipher.ENCRYPT_MODE, key, clearText);
}
public static byte[] decrypt(SecretKey key, byte[] encryptedText) {
return transform(Cipher.DECRYPT_MODE, key, encryptedText);
}
protected static SecretKey keyFromBytes(byte[] keyBytes) {
SecretKeySpec sks = new SecretKeySpec(keyBytes, "AES");
return sks;
}
private static byte[] transform(int mode, SecretKey key, byte[] text) {
if (key == null || text == null) {
throw new NullPointerException();
}
byte[] transformedText = null;
try {
// CBC is used here because the implementation has some trouble
// with ECB (thus the default IV).
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec sks = new SecretKeySpec(key.getEncoded(), "AES");
IvParameterSpec ivs = new IvParameterSpec(defaultIV);
c.init(mode, sks, ivs, rd);
transformedText = c.doFinal(text);
}
catch (GeneralSecurityException e) {
Log.e(TAG, "transform: " + Log.getStackTraceString(e));
}
return transformedText;
}
/**
* Indispensable for reading slashdot.
*
* @return
*/
public static byte[] getSalt() {
byte[] salt = new byte[16];
rd.nextBytes(salt);
return salt;
}
public static byte[] hash(byte[] text, byte[] salt) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
}
catch (NoSuchAlgorithmException e) {
Log.e(TAG, "hash: " + e.getLocalizedMessage());
}
md.update(text);
md.update(salt);
return md.digest();
}
}
Related examples in the same category