String text = name1.getText().toString();
// Sending side
byte[] data = null;
try {
data = text.getBytes("UTF-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
String base64 = Base64.encodeToString(data, Base64.DEFAULT);
was able to encrypt password and will to decrypt the same password but i have something in mind that im not sure of this is my first time trying to encrypt a password. Is it safe to encrypt the password this way because I tried encrypt a password : zxc and the result is just a four letter password (its result is : enhj) so im wondering if it is a safe way to encrypt the password. Any ideas on how to remake the code to make it safer and not easy to decode and ideas on how to decrypt the encrypted password?
UPDATE: This is a sample of encryption and decryption I found at this site here but I cant make it run.
encryption
String password = "password";
int iterationCount = 1000;
int keyLength = 256;
int saltLength = keyLength / 8; // same size as key output
SecureRandom random = new SecureRandom();
byte[] salt = new byte[saltLength];
randomb.nextBytes(salt);
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt,
iterationCount, keyLength);
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
SecretKey key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = new byte[cipher.getBlockSize());
random.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, ivParams);
byte[] ciphertext = cipher.doFinal(plaintext.getBytes("UTF-8"));
decryption
String[] fields = ciphertext.split("]");
byte[] salt = fromBase64(fields[0]);
byte[] iv = fromBase64(fields[1]);
byte[] cipherBytes = fromBase64(fields[2]);
// as above
SecretKey key = deriveKeyPbkdf2(salt, password);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParams = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, key, ivParams);
byte[] plaintext = cipher.doFinal(cipherBytes);
String plainrStr = new String(plaintext , "UTF-8");
You've tagged this cryptography, passwords, and encryption, so I'll answer it as such.
First, Base64 is not actually encryption, it's merely encoding - essentially changing from 8 bit bytes to 6 bit bytes, and your test is perfect - 3*8 bit characters = 24 bits. 24bits/6bits = 4 Base64 characters. I've also verified that enhj is indeed the Base64 encoding of zxc on my own C implementation of Base64. For further evidence of this, note that you didn't provide any encryption key!
Second, for user authentication (which is what I assume you're doing), do not encrypt passwords - that's a major blunder Adobe just made. For user authentication, you don't ever need to see the user's password again - you merely need to verify that they entered the same thing they did before. Thus, when they enter a password the first time, you salt and hash it. The next time, you retrieve the salt you used the first time, and hash the freshly entered password with the same salt (and # of iterations/work factor) - if the result is the same as you have on record, let them in, since giving the same password will get the same result.
The three canonical answers to How to securely hash passwords? are PBKDF2, Bcrypt, and Scrypt. A quick Google search regarding Android password hashing turned up:
How can I make sure password hashing is secure on computers while not being prohibitively slow on mobile devices? and safe to use jBCrypt and recommend it to my organization? which refer to the mindrot jBCrypt Java library and/or the Spring Security variant of jBCrypt
PBKDF2 with SHA256 on android refers to a SpongyCastle 1.47+ implementation of PBKDF2-HMAC-SHA-256 as well references to PBKDF2-HMAC-SHA-1.
PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
generator.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password), salt, iterations);
KeyParameter key = (KeyParameter)generator.generateDerivedMacParameters(keySizeInBits);
The Android-developers blogspot article Using Cryptography to Store Credentials Safely also references PBKDF2-HMAC-SHA-1.
public static SecretKey generateKey(char[] passphraseOrPin, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
// Number of PBKDF2 hardening rounds to use. Larger values increase
// computation time. You should select a value that causes computation
// to take >100ms.
final int iterations = 8000;
// Generate a 160-bit key
final int outputKeyLength = 160;
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
return secretKey;
}
In ALL cases, choose as high an iteration count/work factor as you can stand the delay of (using as fast a library for your chosen algorithm as you can abide by the license of). Your salt should be a cryptographically random series of bytes in the 8 to 16 byte length range.
For PBKDF2 in particular, never use more outputBytes than the native hash size or you give an attacker a comparative advantage - SHA-1's native size is 20 bytes, SHA-256 is 32 bytes, and SHA-512 is 64 bytes natively.
If you really do need encryption rather than authentication, the "Using Cryptography to Store Credentials Safely" link above covers that too, though the better answer is to store the salt and number of iterations/work factor and simply regenerate the key from the password each time - if the data decrypts, it was good. If not, well, bad password.
You are not encrypting anything. You are converting bytes to base64 encoding. You need to use a ciphering algorithm. See http://examples.javacodegeeks.com/core-java/security/simple-symmetric-key-encrypt-decrypt/
Related
I want to mail encrypted log file from my app. Since logs can be larger I have encrypted data using AES and encrypted the key using RSA. Since the AES key is required to decrypt the log, I am sending the encrypted key and logs in the same file.
Question 1: Is this right approach ? If not what is the best approach to follow in this scenario.Below is the code for the same.
public static String encrypt(String data) {
StringBuilder encryptedData = new StringBuilder();
try {
// Generate AES key.
KeyGenerator generator = KeyGenerator.getInstance("AES");
// The AES key size in number of bits.
generator.init(256);
SecretKey secKey = generator.generateKey();
// Initialize AES Cipher, IV and encrypt string.
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, secKey, new IvParameterSpec(new byte[16]));
byte[] byteCipherText = aesCipher.doFinal(data.getBytes());
String encryptedText = Base64.encodeToString(byteCipherText, Base64.DEFAULT);
// Initialize RSA Cipher and generate public key.
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(Base64.decode(PUBLIC_KEY, Base64.DEFAULT));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey puKey = keyFactory.generatePublic(publicSpec);
cipher.init(Cipher.PUBLIC_KEY, puKey);
// Encrypt key and text.
byte[] encryptedKey = cipher.doFinal(secKey.getEncoded());
String aesKey = Base64.encodeToString(encryptedKey, Base64.DEFAULT);
encryptedData.append(aesKey);
encryptedData.append(encryptedText);
} catch (Exception e) {
e.printStackTrace();
}
return encryptedData.toString();
}
Since the AES key is required to decrypt the log, I am sending the encrypted key and logs in the same file.
Question 1: Is this right approach ? If not what is the best approach to follow in this scenario.Below is the code for the same.
The approach is correct, what I'm missing is authentication (HMAC, GCM, ...).
There are some standards how to bundle the encrypted key, content and authentication together (e.g. CMS, PKCS7, OpenPGP, ..) however if it's for your own application, you may do it your way (don't bother with standards).
If you want to use RSA use RSA-KEM
Well, using RSA KEM you may save a little of performance skipping the padding, but I'd try if it is feasible for you. As well there's an issue when encrypting the same key material with different public keys.
I'd keep it simple - just use the properly padded RSA encryption.
I'd suggest to use OAEP padding RSA/ECB/OAEPWithSHA-256AndMGF1Padding instead of PKCS1Padding (OAEP is considered newer/safer)
I want to an Android database using a symmetric algorithm (AES).
In cryptography is there a function as below
some_function( a-4-digit-PIN, some_salt) {
return some_hash;
}
The 4 digit PIN and salt are complimentary and can vary BUT the function should produce the same hash whichever combination they may be.
The idea is to have the salt stored on the device and the 4 digit PIN sen to the user via text messaging (to support offline situations).
Each user will have his own salt store on the phone (these salts are periodically updated from a central database when the phone can connect to the internet).
The hash produced by this function is used to generate a password for the database, hence why it should always be the same.
In essence, is there a function/algorithms where multiple PIN-salt pairs produce the same a hash.
You can use PBKDF2WithHmacSHA1 and provide a salt. It will generate a SecretKey from your password after some iterations. See in this link a full example of AES encryption and salt generation:
http://www.coderzheaven.com/2013/03/19/encrypt-decrypt-file-aes-algorithm-android/
public static SecretKey generateKey(char[] passphraseOrPin, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
// Number of PBKDF2 hardening rounds to use. Larger values increase
// computation time. You should select a value that causes computation
// to take >100ms.
final int iterations = 1000;
// Generate a 256-bit key
final int outputKeyLength = 256;
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
return secretKey;
}
I'm trying to implement AES encryption ,in Android, which uses a pass phrase to generate the SecretKey. I'm passing the same byte[]
as initialization vector to the ciphers and as salt when generating the SecretKey with PBKDF2.
The passphrase is supplied by the user each time an encryption/decryption is needed.
As of now, I only need to encrypt one value in my database (if that makes any difference).
Questions:
I'm wondering if using the same byte[] as IV and salt weakens the encryption?
Is there a reason to switch from CBC to GCM other then the data integrity functionality GCM provides?
I've read about CBC being prone to BEAST attack, is using a new random IV per message, as demonstrated bellow, mitigates BEAST attack?
Current source code:
public class AesEncryption {
private static final int KEY_SIZE = 16;
private static final int OUTPUT_KEY_LENGTH = 256;
private static final int ITERATIONS = 1000;
private String mPassphraseOrPin;
public AesEncryption(String passphraseOrPin) {
mPassphraseOrPin = passphraseOrPin;
}
public void encrypt(String id, String textToEncrypt) throws Exception {
byte[] iv = getIv();
SecretKey secretKey = generateKey(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
byte[] cipherText = cipher.doFinal(textToEncrypt.getBytes("utf-8"));
byte[] ivCipherText = arrayConcat(iv, cipherText);
String encryptedText = Base64.encodeToString(ivCipherText, Base64.NO_WRAP);
storeEncryptedTextInDb(id, encryptedText);
}
public String decrypt(String id) throws Exception {
String encryptedText = getEncryptedTextFromDb(id);
byte[] ivCipherText = Base64.decode(encryptedText, Base64.NO_WRAP);
byte[] iv = Arrays.copyOfRange(ivCipherText, 0, KEY_SIZE);
byte[] cipherText = Arrays.copyOfRange(ivCipherText, KEY_SIZE, ivCipherText.length);
SecretKey secretKey = generateKey(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
String decrypted = new String(cipher.doFinal(cipherText), "utf-8");
return decrypted;
}
public SecretKey generateKey(byte[] salt) throws Exception {
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(mPassphraseOrPin.toCharArray(), salt, ITERATIONS, OUTPUT_KEY_LENGTH);
SecretKey tmp = secretKeyFactory.generateSecret(keySpec);
return new SecretKeySpec(tmp.getEncoded(), "AES");
}
private byte[] getIv() {
byte[] salt = new byte[KEY_SIZE];
new SecureRandom().nextBytes(salt);
return salt;
}
private byte[] arrayConcat(byte[] one, byte[] two) {
byte[] combined = new byte[one.length + two.length];
for (int i = 0; i < combined.length; ++i) {
combined[i] = i < one.length ? one[i] : two[i - one.length];
}
return combined;
}
}
I'm wondering if using the same byte[] as IV and salt weakens the encryption?
Yes it does.
For the salt: if you don't randomize the salt then an attacker can pre-calculate a table with passwords and password hashes. This is called a rainbow table. Furthermore, if anybody has the same password it would result in the same key. It's strongly recommended to generate a salt per user and - if feasible - a new salt each time the value is re-encrypted.
For the IV: if you re-encrypt starting blocks containing the same plaintext then the ciphertext will repeat blocks. An attacker can use this to extract information from this. Simple example: encrypting "Yes" or "No" twice will clearly be distinguishable from first encrypting "Yes" and then "No". Generally you should generate a random IV and store it with the ciphertext. This is recommended even if the salt (and thus the key) is randomized. It of course depends on your threat model if this makes a difference in the real world.
Is there a reason to switch from CBC to GCM other then the data integrity functionallity GCM provides?
GCM provides integrity and authenticity of the plaintext. Functionally it's just AES in CTR mode with an authentication tag. It depends on your threat model if you need integrity and authenticity of the plaintext (and possibly Additional Authenticated Data or AAD). It won't add any functionality otherwise.
If you're just after keeping your data confidential then you may not need GCM. If you want to protect it against changes made by an attacker then you do need it. In that case however you also need to protect against replay attacks.
I've read about CBC being prone to BEAST attack, is using a new random IV per message, as demonstrated bellow, mitigates BEAST attack?
The BEAST attack is a browser based attack against SSL/TLS. By definition it doesn't apply against database encryption, especially with regards to data at rest. A whole slew of attacks can possibly be raised, but BEAST depends on dynamic data within a TLS connection.
Notes:
Length based attacks are often forgotten as ciphers / cipher modes do not protect against them. They may be applicable none-the-less. GCM leaks slightly more information about the length of the plaintext compared to CBC.
It may also be interesting for an attacker to see if a value is re-encrypted or not.
1000 is not considered a secure iteration count / work factor anymore. You may want to upgrade it (and create a upgrade strategy).
I had tried to run the following AES/ CBC/ PKCS5Padding encryption and decryption code, with SHA-1 as key generation, in Nexus 5. It works very well so far.
However, my only concern is, Is AES/ CBC/ PKCS5Padding encryption decryption algorithm and SHA-1 hashing algorithm available in all type of Android devices?
Is there any chance that the following code will fail to run on certain Android devices? If so, is there any fall back plan?
AES/ CBC/ PKCS5Padding
// http://stackoverflow.com/questions/3451670/java-aes-and-using-my-own-key
public static byte[] generateKey(String key) throws GeneralSecurityException, UnsupportedEncodingException {
byte[] binary = key.getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
binary = sha.digest(binary);
// Use only first 128 bit.
binary = Arrays.copyOf(binary, 16);
return binary;
}
// http://stackoverflow.com/questions/17322002/what-causes-the-error-java-security-invalidkeyexception-parameters-missing
public static String encrypt(byte[] key, String value) throws GeneralSecurityException {
// Argument validation.
if (key.length != 16) {
throw new IllegalArgumentException("Invalid key size.");
}
// Setup AES tool.
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
// Do the job with AES tool.
byte[] original = value.getBytes(Charset.forName("UTF-8"));
byte[] binary = cipher.doFinal(original);
return Base64.encodeToString(binary, Base64.DEFAULT);
}
// // http://stackoverflow.com/questions/17322002/what-causes-the-error-java-security-invalidkeyexception-parameters-missing
public static String decrypt(byte[] key, String encrypted) throws GeneralSecurityException {
// Argument validation.
if (key.length != 16) {
throw new IllegalArgumentException("Invalid key size.");
}
// Setup AES tool.
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
// Do the job with AES tool.
byte[] binary = Base64.decode(encrypted, Base64.DEFAULT);
byte[] original = cipher.doFinal(binary);
return new String(original, Charset.forName("UTF-8"));
}
Usage
byte[] key = generateKey("my secret key");
String ciphertext = encrypt(key, "my plain content");
String plainContent = decrypt(key, ciphertext);
No, it's unlikely to the extreme that it will fail. The Android API has been derived from the Java API's. The Java API's have contained the "AES/CBC/PKCS5Padding" since version 1.4.
As for "SHA-1", that's an even older algorithm, which has been supported since time began.
Beware not to use "PKCS7Padding" instead. Java uses "PKCS5Padding" as replacement, "PKCS7Padding" support may be sketchy even if it means the same thing.
Note that you should be using password based encryption (PBE) instead of AES/CBC and SHA-1. Especially using SHA-1 as key derivation method is particularly dangerous as you don't use a salt or work factor as a good Password Based Key Derivation Function such as PBKDF2 should. Basically only do this if you know your password contains enough entropy.
Using an all zero IV for the same key is worse though (as already indicated in the comments). It lets attackers find repeats of (the starting blocks of) plaintext input. Authenticated encryption (e.g. using HMAC-SHA-1) is always recommended and more or less required for transport mode encryption (as opposed to in-place encryption where plaintext/padding oracle attacks are not possible).
This isn't answering your question directly, but...
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
Do not use this construct! It will break any security you think you're getting!
This invocation initialises your cipher object with an all-zeros initialisation vector. This is a very very very bad thing, especially with CBC: CBC is quite malleable, and doesn't do any integrity-protection. Make sure you generate your IV using SecureRandom or similar, and preferably use GCM or CCM.
I'm currently implementing a symmetric en-/decryption using AES 256 on Android, inspired by this post:
Java 256bit AES Encryption.
The purpose of my implementation is that I want to encrypt the data in a database.
For key generation I use the following constructor which takes a char[] password:
public Cryptography(char[] password) throws NoSuchAlgorithmException,
InvalidKeySpecException, NoSuchPaddingException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
KeySpec spec = new PBEKeySpec(password, salt, 1024, 256);
secretKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
cipher = Cipher.getInstance(AES/CBC/PKCS5Padding);
}
So when I start my Activity in Android I initialize a new instance of my Cryptography class and therefore get a generated key. The salt is a fixed random byte[] of 16 bytes. So that means that I always get the same key. The reason for that later.
Now after I got an object in one Activity I can use the following encrypt and decrypt methods with always the same key:
public byte[] encrypt(String cleartext) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException,
UnsupportedEncodingException, InvalidParameterSpecException {
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encText = cipher.doFinal(cleartext.getBytes(CHARSET_NAME));
byte[] iv = cipher.getParameters()
.getParameterSpec(IvParameterSpec.class).getIV();
byte[] enc = new byte[IV_SIZE + encText.length];
for (int i = 0; i < enc.length; i++) {
if (i < IV_SIZE)
enc[i] = iv[i];
else if (i < enc.length)
enc[i] = encText[i - IV_SIZE];
}
return enc;
}
public String decrypt(byte[] encryptedText) throws InvalidKeyException,
InvalidAlgorithmParameterException, UnsupportedEncodingException,
IllegalBlockSizeException, BadPaddingException {
byte[] iv = new byte[IV_SIZE];
byte[] dec = new byte[encryptedText.length - IV_SIZE];
for (int i = 0; i < encryptedText.length; i++) {
if (i < IV_SIZE)
iv[i] = encryptedText[i];
else if (i < encryptedText.length)
dec[i - IV_SIZE] = encryptedText[i];
}
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
return new String(cipher.doFinal(dec), CHARSET_NAME);
}
As you can see, I save a fresh new IV along with the ciphertext everytime I encrypt a message.
In conclusion: I use ONE encryption key, ONE random salt and a new IV for EVERY field in a database table.
First I wanted to generate a new key with a new salt and a new IV everytime I encrypt ONE field in the database table and save the required salt and IV with along with the ciphertext, or at least for one table row. But the reason why I did it like above mentioned is, because generating a key on an Android device takes to much time. I tested in on an emulator, but it took about two seconds for generating a key. This is why I just generated one key when an Activity is started.
So finally my question:
With my approach, is it secure enough by using just one key, but fresh random IV's for every message? Currently, I don't see another way to make it as secure as possible by keeping it in balance with performance.
I hope it is clear enough what I wrote and somebody could give me some advice on that.
Kind Regards
xoidberg
I believe the question is not relevant for you (xoidberg), but it might be relevant for some other people.
From what I understand - you use the salt to create a (securely random) key from password. If every user has a random (different) salt - it is ok. Otherwise it might be problematic.
I believe that this is what you did, so it seems (to me) to be ok.
I just want to mention that usually you want to use salts when you save hash function of some values (usually password). Hash functions like MD5 or the SHAs do not have a key, and you must add randomness for this purpose. This is why you need the salt, and this is why in this case you usually need random salt for each value (if you just save passwords hashes with the same salt, one can detect the most common hashes and learn that the password of the users with the most common hash is 123456). In your case - every user needs a unique salt.
About the IV - you really need a random one each time (so it's ok).