Rijndael.java
/*
* Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
* Original author: Edmund Wagner
* Creation date: 31.05.2007
*
* the unrar licence applies to all junrar source and binary distributions
* you are not allowed to use this source to re-create the RAR compression algorithm
* Source: $HeadURL$
* Last changed: $LastChangedDate$
*
* Here some html entities which can be used for escaping javadoc tags:
* "&": "&" or "&"
* "<": "<" or "<"
* ">": ">" or ">"
* "@": "@"
*/
package com.github.junrar.crypt;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* DOCUMENT ME
*
* @author $LastChangedBy$
* @version $LastChangedRevision$
*/
public class Rijndael {
public static Cipher buildDecipherer(final String password, byte[] salt) throws IOException,
NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchPaddingException {
if (password == null) {
throw new InvalidAlgorithmParameterException("password should be specified");
}
byte[] AESInit = new byte[16];
byte[] AESKey = new byte[16];
int rawLength = 2 * password.length();
byte[] rawpsw = new byte[rawLength + 8];
byte[] pwd = password.getBytes();
for (int i = 0; i < password.length(); i++) {
rawpsw[i * 2] = pwd[i];
rawpsw[i * 2 + 1] = 0;
}
System.arraycopy(salt, 0, rawpsw, rawLength, salt.length);
MessageDigest sha = MessageDigest.getInstance("sha-1");
final int HashRounds = 0x40000;
final int xh = HashRounds / 16;
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] digest = null;
for (int i = 0; i < HashRounds; i++) {
bout.write(rawpsw);
bout.write((byte) i);
bout.write((byte) (i >>> 8));
bout.write((byte) (i >>> 16));
if (i % xh == 0) {
byte[] input = bout.toByteArray();
sha.update(input);
digest = sha.digest();
AESInit[i / xh] = digest[19];
}
}
sha.update(bout.toByteArray());
digest = sha.digest();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
AESKey[i * 4 + j] = (byte) (((digest[i * 4] * 0x1000000) & 0xff000000
| ((digest[i * 4 + 1] * 0x10000) & 0xff0000) | ((digest[i * 4 + 2] * 0x100) & 0xff00)
| digest[i * 4 + 3] & 0xff) >>> (j * 8));
}
}
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(AESKey, "AES"), new IvParameterSpec(AESInit));
return cipher;
}
}