Related
In Java code, i have source work well, this is use for encrypt:
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class HelloWorld{
private static final String hexKey = "B8EE12E123C0E300A202074A153CC0D27D739357480FFFFFFFFFFFFFFFFFFFEF";
public static void main(String []args){
System.out.println("Encryt ==== ");
String textToEncrypt = "From=ABC&Key=FootID1234&Value=ResultValue2324";
String encryptedText = encrypt(textToEncrypt);
System.out.println(encryptedText);
System.out.println("Decrypt ==== ");
String decryptedText = decrypt(encryptedText);
System.out.println(decryptedText);
}
public static String encrypt (String plainText) {
String encryptedText = null;
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
SecretKeySpec secretKey = new SecretKeySpec(hexToBytes(hexKey), "AES");
IvParameterSpec ivparameterspec = new IvParameterSpec(hexKey.getBytes(), 0, 16);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivparameterspec);
byte[] cipherText = cipher.doFinal(plainText.getBytes("UTF8"));
encryptedText = bytesToHex(cipherText);
} catch (Exception E) {
System.out.println("Encrypt Exception : " + E.getMessage());
}
return encryptedText;
}
public static String decrypt(String encryptedText) {
String decryptedText = null;
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
SecretKeySpec secretKey = new SecretKeySpec(hexToBytes(hexKey), "AES");
IvParameterSpec ivparameterspec = new IvParameterSpec(hexKey.getBytes("UTF8"), 0, 16);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivparameterspec);
byte[] cipherText = hexToBytes(encryptedText);
byte[] dcrbyte = cipher.doFinal(cipherText);
decryptedText = new String(dcrbyte, "UTF-8");
} catch (Exception E) {
System.out.println("Encrypt Exception : " + E.getMessage());
}
return decryptedText;
}
private static byte[] hexToBytes(String hexStr) {
byte[] val = new byte[hexStr.length() / 2];
for (int i = 0; i < val.length; i++) {
int idx = i * 2;
int j = Integer.parseInt(hexStr.substring(idx, idx + 2), 16);
val[i] = (byte) j;
}
return val;
}
private static String bytesToHex(byte[] hashInBytes) {
char[] hexArray = "0123456789ABCDEF".toCharArray();
char[] hexChars = new char[hashInBytes.length * 2];
for (int i = 0; i < hashInBytes.length; i++) {
int v = hashInBytes[i] & 0xFF;
hexChars[i * 2] = hexArray[v >>> 4];
hexChars[i * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
}
And in c#, i try to write decryptAes() function like this:
public static class Encryption
{
// use these parameters to test decryptAes()
//string key = "B8EE12E123C0E300A202074A153CC0D27D739357480FFFFFFFFFFFFFFFFFFFEF";
//string textToDecrypt = "756AD4D80E2CF1E289D55A23E092F012E8D5F372A343A419BC87F77B6335F04EFB41C3B56F5CDA167F90F67CD672A186";
public static string decryptAes(string key, string textToDecrypt)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
// Assumed Mode and padding values.
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7;
// AssumedKeySize and BlockSize values.
rijndaelCipher.KeySize = 0x80; //128
rijndaelCipher.BlockSize = 0x80;
// Convert Hex keys to byte Array.
byte[] encryptedData = HexToBytes(textToDecrypt);
//byte[] pwdBytes = System.Text.Encoding.GetEncoding("UTF-8").GetBytes(key);
byte[] pwdBytes = HexToBytes(key);
byte[] keyBytes = new byte[0x10]; //16
int len = pwdBytes.Length;
if (len > keyBytes.Length)
{
len = keyBytes.Length;
}
Array.Copy(pwdBytes, keyBytes, len);
rijndaelCipher.Key = keyBytes;
rijndaelCipher.IV = keyBytes;
// Decrypt data
byte[] plainText = rijndaelCipher.CreateDecryptor()
.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
return Encoding.UTF8.GetString(plainText);
}
public static byte[] HexToBytes(string str)
{
if (str.Length == 0 || str.Length % 2 != 0)
return new byte[0];
byte[] buffer = new byte[str.Length / 2];
char c;
for (int bx = 0, sx = 0; bx < buffer.Length; ++bx, ++sx)
{
// Convert first half of byte
c = str[sx];
buffer[bx] = (byte)((c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0')) << 4);
// Convert second half of byte
c = str[++sx];
buffer[bx] |= (byte)(c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0'));
}
return buffer;
}
public static string ByteToHex(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString().ToUpper();
}
}
But the c# decryptAes() function does not work as i expect. An error
System.Security.Cryptography.CryptographicException: 'Padding is invalid and cannot be removed.'
has occured at line rijndaelCipher.Padding = PaddingMode.PKCS7;
When i change to rijndaelCipher.Padding = PaddingMode.None, it does not work as i expect, the c# result is not the same as the result of java.
Please help, any advice would be appreciated!
Thanks!
You need to explicitly set the padding for both encryption and decryption. Unless you have a reason to do otherwise, use PKCS#7 padding.
rijndaelCipher.Padding=PaddingMode.none;
The java code below generates a SHA-256 hash of the input msg, using the key. However, all my attempts to write code that does same operation in C# have not yielded the same results given same input. I would need help getting the C# equivalent as I have tried a lot already with little success.
I think I've been able to translate most of the code into C# correctly, apart from the part which updates the digest (m.update()), first with the key, then later with the message before hashing.
JAVA CODE
public static String generateHash256Value(String msg, String key) {
MessageDigest m = null;
String hashText = null;
System.out.println("Value to hash::::::::::" + msg);
byte[] actualKeyBytes = HexToByte(secret_key);
try {
m = MessageDigest.getInstance("SHA-256");
m.update(actualKeyBytes, 0, actualKeyBytes.length);
try {
m.update(msg.getBytes("UTF-8"), 0, msg.length());
}
catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
}
hashText = new BigInteger(1, m.digest()).toString(16);
if (hashText.length() < 64) { //must be 64 in length
int numberOfZeroes = 64 - hashText.length();
String zeroes = "";
for (int i = 0; i < numberOfZeroes; i++) {
zeroes = zeroes + "0";
}
hashText = zeroes + hashText;
}
}
catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
hashText = hashText.toUpperCase();
return hashText;
}
public static byte[] hex2Byte(String str) {
byte[] bytes = new byte[str.length() / 2];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) Integer
.parseInt(str.substring(2 * i, 2 * i + 2), 16);
}
return bytes;
}
C# CODE (attempt)
private static string DoSpecialSha256Hash(string message, string key)
{
String hashText = null;
Console.WriteLine("Value to hash::::::::::" + message);
byte[] keyByte = hex2Byte(key);
Encoding encoder = new System.Text.UTF8Encoding();
var hashAlgo = new SHA256Managed();
var messageBytes = encoder.GetBytes(message);
var toDigest = Combine(keyByte, messageBytes);
hashText = ByteToString(hashAlgo.ComputeHash(toDigest, 0, message.Length));
if (hashText.Length < 64)
{ //must be 64 in length
int numberOfZeroes = 64 - hashText.Length;
String zeroes = "";
for (int i = 0; i < numberOfZeroes; i++)
{
zeroes = zeroes + "0";
}
hashText = zeroes + hashText;
}
hashText = hashText.ToUpper();
return hashText;
}
public static byte[] HexToByte(String hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
private static string ByteToString(byte[] buff)
{
string sbinary = "";
for (int i = 0; i < buff.Length; i++)
{
sbinary += buff[i].ToString("X2"); // hex format
}
return (sbinary);
}
private static byte[] Combine(params byte[][] arrays)
{
byte[] rv = new byte[arrays.Sum(a => a.Length)];
int offset = 0;
foreach (byte[] array in arrays)
{
System.Buffer.BlockCopy(array, 0, rv, offset, array.Length);
offset += array.Length;
}
return rv;
}
Thanks,
In order to properly understand the operation of the standard security handler in pdf
I am trying to reconstruct the entry /o e /u of the encryption dictionary from a previously encrypted pdf.
The encryption dictionary over /o and /u contains:
/P -1852
/CF
<<
/StdCF
<<
/AuthEvent /DocOpen
/Length 16
/CFM/V2
>>
>>
/R 4
/StmF /StdCF
/Filter/Standard
I managed to successfully reconstruct /o but I can not rebuild /u
main:
public static void main(String[] args) {
String docID;
byte[] userPass=null;
byte[] ownerPass=null;
try {
userPass = userPassString.getBytes("ISO-8859-1");
ownerPass = ownerPassString.getBytes("ISO-8859-1");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
PDDocument doc=PDDocument.load(outPDfDir + "/EncryptedDocument_rc4_128.pdf");
if (doc.isEncrypted()){
EncryptDocument encrypt = new EncryptDocument(userPass,ownerPass,outPDfDir,doc.getEncryptionDictionary().getLength());
encrypt.setRevision(doc.getEncryptionDictionary().getRevision());
encrypt.setVersion(doc.getEncryptionDictionary().getVersion());
COSArray cosArray = doc.getDocument().getDocumentID();
docID=cosArray.getString(0); //only first entry of the array
byte[][] keys = encrypt.computeKeys(userPass, ownerPass, doc.getEncryptionDictionary().getPermissions(), docID.getBytes());
byte[] originalUserKey = doc.getEncryptionDictionary().getUserKey();
byte[] originalownerKey = doc.getEncryptionDictionary().getOwnerKey();
System.out.println(toHex(originalUserKey));
System.out.println(toHex(keys[1]));
if (Arrays.equals(originalUserKey,keys[1])){
System.out.println("User correctly authenticated");
}else{
System.out.println("wrong user password");
}
if (Arrays.equals(originalownerKey,keys[0])){
System.out.println("Owner correctly authenticated");
}else{
System.out.println("wrong user password");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
Encrypt class
public class EncryptDocument {
private ARCFour rc4 = new ARCFour();
public static final byte[] ENCRYPT_PADDING = new byte[]{(byte)40, (byte)-65, (byte)78, (byte)94, (byte)78, (byte)117, (byte)-118, (byte)65, (byte)100, (byte)0, (byte)78, (byte)86, (byte)-1, (byte)-6, (byte)1, (byte)8, (byte)46, (byte)46, (byte)0, (byte)-74, (byte)-48, (byte)104, (byte)62, (byte)-128, (byte)47, (byte)12, (byte)-87, (byte)-2, (byte)100, (byte)83, (byte)105, (byte)122};
byte[] userPass;
byte[] ownerPass;
String destPath;
int revision;
int version;
private static final byte[] pad = new byte[]{(byte)40, (byte)-65, (byte)78, (byte)94, (byte)78, (byte)117, (byte)-118, (byte)65, (byte)100, (byte)0, (byte)78, (byte)86, (byte)-1, (byte)-6, (byte)1, (byte)8, (byte)46, (byte)46, (byte)0, (byte)-74, (byte)-48, (byte)104, (byte)62, (byte)-128, (byte)47, (byte)12, (byte)-87, (byte)-2, (byte)100, (byte)83, (byte)105, (byte)122};
private int keyLength;
public EncryptDocument(byte[] userPass, byte[] ownerPass, String destPath,int keylength) {
this.userPass = userPass;
this.ownerPass = ownerPass;
this.destPath = destPath;
this.keyLength=keylength;
}
public byte[][] computeKeys(byte[] userPass, byte[] ownPass, int permissions, byte[] documentId) {
//pad both user and owner pass
byte[] userPad = padPassword(userPass);
byte[] ownerPad = padPassword(ownPass);
byte[][] data = new byte[2][32];
byte[] userKey = new byte[0];
byte[] encryptionKey;
permissions= computePermissions(permissions);
byte[] ownerKey = new byte[0];
try {
ownerKey = computeOwnerKey(userPad, ownerPad);
encryptionKey = computeEncryptionKey(userPad,ownerKey,documentId,permissions);
userKey = computeUserKey(userPad,ownerKey,permissions,documentId,encryptionKey);
} catch (IOException e) {
e.printStackTrace();
}
data[0]=ownerKey;
data[1]=userKey;
return data;
}
private byte[] computeUserKey(byte[] userPad, byte[] ownerKey, int permissions, byte[] documentId, byte[] mkey) throws IOException {
//algorithm 5
byte[] digest;
ByteArrayOutputStream userKey = new ByteArrayOutputStream();
ARCFour rc4 = new ARCFour();
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
md5.update(pad); // step b
digest = md5.digest(documentId); //c
//build the input of rc4 encryption
userKey.write(digest);
byte[] iterationKey = new byte[mkey.length];
//encrypt it first time plus other 19 times
for (int i = 0; i < 20; ++i) {
System.arraycopy(mkey, 0, iterationKey, 0, iterationKey.length);
for (int input = 0; input < iterationKey.length; ++input) {
iterationKey[input] = (byte) (iterationKey[input] ^ i);
}
rc4.setKey(iterationKey);
ByteArrayInputStream tmpRes = new ByteArrayInputStream(userKey.toByteArray());
userKey.reset();
rc4.write(tmpRes, userKey);
}
return userKey.toByteArray();
}
private byte[] computeEncryptionKey(byte[] userPad,byte[] ownerKey, byte[] documentId,int permissions){
//initialize hash function
MessageDigest md5 = null;
byte[] encryptedKey =new byte[keyLength / 8];
byte[] digest;
try {
md5 = MessageDigest.getInstance("MD5"); //md5.reset()
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
md5.update(userPad);///pass the padded user password (step b)
md5.update(ownerKey); //pass o entry to the hash function (step c)
byte[] ext = int_to_bb_le(permissions); //new byte[]{(byte)permissions, (byte)(permissions >> 8), (byte)(permissions >> 16), (byte)(permissions >> 24)};
md5.update(ext, 0, 4); //pass permission to the hash function stp d
md5.update(documentId); //pass first element of document id (step e)
if (this.revision>=4)
md5.update(new byte[]{(byte)-1, (byte)-1, (byte)-1, (byte)-1}); //metadata not encryped --> add padding (step f)
digest = md5.digest();
//compute encryption key step g
if(revision == 3 || revision == 4) { //do 50 times step h
for(int k = 0; k < 50; ++k) {
md5.reset();
md5.update(digest,0,keyLength / 8);
digest=md5.digest();
}
}
System.arraycopy(digest, 0, encryptedKey, 0, encryptedKey.length);
return encryptedKey;
}
private byte[] computeOwnerKey(byte[] userPad, byte[] ownerPad) throws IOException {
MessageDigest md5 = null;
ARCFour rc4 = new ARCFour();
try {
md5 = MessageDigest.getInstance("MD5"); //md5.reset()
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte[] digest = md5.digest(ownerPad);
byte[] mkey = new byte[this.keyLength / 8];
int i;
for (i = 0; i < 50; ++i) {
md5.update(digest, 0, mkey.length);
System.arraycopy(md5.digest(), 0, digest, 0, mkey.length);
}
//encrypt the padded user password using the result of md5 computation on owner padded password
//revision >3 ==> do it 19 times
ByteArrayOutputStream ownerKey = new ByteArrayOutputStream();
//System.arraycopy(userPad, 0, ownerKey, 0, 32);
rc4.write(new ByteArrayInputStream(userPad), ownerKey);
byte[] iterationKey = new byte[mkey.length];
for (i = 0; i < 20; ++i) {
System.arraycopy(mkey, 0, iterationKey, 0, mkey.length);
//prepare encryption key bitwhise xor between encrypted owner padded password and iteration counter
for (int j = 0; j < iterationKey.length; ++j) {
iterationKey[j] = (byte) (digest[j] ^ i);
}
//encrypt with arc4
rc4.setKey(iterationKey);
ByteArrayInputStream tmpres = new ByteArrayInputStream(ownerKey.toByteArray());
ownerKey.reset();
rc4.write(tmpres, ownerKey);
}
//at the 19 invocation the own key is obtained
return ownerKey.toByteArray();
}
public int computePermissions(int permissions){
permissions |= this.revision != 3 && this.revision != 4 && this.revision != 5?-64:-3904;
permissions &= -4;
return permissions;
}
public byte[] padPassword(byte[] password) {
byte[] userPad = new byte[32];
if(password == null) {
System.arraycopy(pad, 0, userPad, 0, 32);
} else {
System.arraycopy(password, 0, userPad, 0, Math.min(password.length, 32));
if(password.length < 32) {
System.arraycopy(pad, 0, userPad, password.length, 32 - password.length);
}
}
return userPad;
}
public static byte[] int_to_bb_le(int myInteger){
return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(myInteger).allocatelocaterray();
}
}
someone is able to understand where I'm wrong?
I have a requirement to AES Encrypt (with initial vector) an NSString value.But it gives different output on comparing with the java code provided below.In Java it is delivering the correct result.What could be the reason?
For that I have used the code below:
iOS
- (NSData *)AES256EncryptWithKey:(NSString *)key
{
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES128 ,
INTIAL_VECTOR /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer); //free the buffer;
return nil;
}
- (NSString*)hexStringFromData:(NSData *)data
{
unichar* hexChars = (unichar*)malloc(sizeof(unichar) * (data.length*2));
unsigned char* bytes = (unsigned char*)data.bytes;
for (NSUInteger i = 0; i < data.length; i++) {
unichar c = bytes[i] / 16;
if (c < 10) c += '0';
else c += 'a' - 10;
hexChars[i*2] = c;
c = bytes[i] % 16;
if (c < 10) c += '0';
else c += 'a' - 10;
hexChars[i*2+1] = c;
}
NSString* retVal = [[NSString alloc] initWithCharactersNoCopy:hexChars
length:data.length*2
freeWhenDone:YES];
return [retVal autorelease];
}
The implementation snippet is :
NSData *InputData = [#"mahi" dataUsingEncoding:NSUTF8StringEncoding];
NSData *encryptedData = [InputData AES256EncryptWithKey:ENCRYPTION_KEY];
NSString *encryptedHexString = [self hexStringFromData:encryptedData];
NSLog(#"Encrypted HexString : %#",encryptedHexString);
Java
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class MCrypt {
private String iv = "fedcba9876543210";
private IvParameterSpec ivspec;
private SecretKeySpec keyspec;
private Cipher cipher;
private String SecretKey = "0123456789abcdef";
public MCrypt()
{
ivspec = new IvParameterSpec(iv.getBytes());
keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public byte[] encrypt(String text) throws Exception
{
if(text == null || text.length() == 0)
throw new Exception("Empty string");
byte[] encrypted = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
encrypted = cipher.doFinal(padString(text).getBytes());
} catch (Exception e)
{
throw new Exception("[encrypt] " + e.getMessage());
}
return encrypted;
}
public byte[] decrypt(String code) throws Exception
{
if(code == null || code.length() == 0)
throw new Exception("Empty string");
byte[] decrypted = null;
try {
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
decrypted = cipher.doFinal(hexToBytes(code));
} catch (Exception e)
{
throw new Exception("[decrypt] " + e.getMessage());
}
return decrypted;
}
public static String bytesToHex(byte[] data)
{
if (data==null)
{
return null;
}
int len = data.length;
String str = "";
for (int i=0; i<len; i++) {
if ((data[i]&0xFF)<16)
str = str + "0" + java.lang.Integer.toHexString(data[i]&0xFF);
else
str = str + java.lang.Integer.toHexString(data[i]&0xFF);
}
return str;
}
public static byte[] hexToBytes(String str) {
if (str==null) {
return null;
} else if (str.length() < 2) {
return null;
} else {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i=0; i<len; i++) {
buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16);
}
return buffer;
}
}
private static String padString(String source)
{
char paddingChar = ' ';
int size = 16;
int x = source.length() % size;
int padLength = size - x;
for (int i = 0; i < padLength; i++)
{
source += paddingChar;
}
return source;
}
}
after struggling for a while, I figured that I should bring my question here as I do not really know exactly what I am doing. Basically, I am using a somewhat modified version of the cryptastic version found here.
I am currently base64 encoding everything, then converting to hexidecimal in order to keep the data the same between the two langauges. Right now, I have managed to get decryption from PHP to work, but keep coming across errors when I try to encrypt. I am using BouncyCastle... and for some reason in the decrypt when I do an init, instead of using false it will only work with true (which the docs say is for encryption...)
Anyway, here is my class thus far if anyone has a chance to look at it that would be great.
Technically, decrypt is working only because I have a hack function to remove padding as the ZeroByteEncoding isn't working properly either.
So, I am able to decrypt from the PHP cryptastic, but not encrypt properly so that it can decrypt (it throws an error in my stringToHexidecimal then)
public class Cryptastic {
public final static String CHARSET = "US-ASCII";
public byte[] encrypt(String toEncrypt, byte[] keyBytes, boolean base64Encode)
{
try
{
toEncrypt = serialize(toEncrypt);
byte[] newEncrypt = toEncrypt.getBytes(CHARSET);
BlockCipher blockCipher = new RijndaelEngine(256);
SecureRandom secureRandom = new SecureRandom();
byte[] iv = new byte[32];
secureRandom.nextBytes(iv);
CipherParameters cipherParameters = new ParametersWithIV(new KeyParameter(keyBytes), iv);
RijndaelEngine rijndael = new RijndaelEngine(256);
SICBlockCipher ctrMode = new SICBlockCipher(rijndael);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(ctrMode, new ZeroBytePadding());
cipher.init(true, cipherParameters);
int size = cipher.getOutputSize(newEncrypt.length);
byte[] encrypted = new byte[size];
System.out.println(displayBytes(encrypted, false));
int outputLength = cipher.processBytes(newEncrypt, 0, newEncrypt.length, encrypted, 0);
cipher.doFinal(encrypted, outputLength);
if(base64Encode)
{
encrypted = Base64.encode(encrypted);
}
byte[] temp = new byte[encrypted.length + 32];
for(int i = 0; i < iv.length; i++)
{
temp[i] = iv[i];
}
for(int i = iv.length; i < temp.length; i++)
{
temp[i] = encrypted[i - iv.length];
}
encrypted = temp;
byte[] mac = generateKey(encrypted, keyBytes, 1000, 32);
temp = new byte[encrypted.length + mac.length];
for(int i = 0; i < encrypted.length; i++)
{
temp[i] = encrypted[i];
}
for(int i = encrypted.length; i < temp.length; i++)
{
temp[i] = mac[i - encrypted.length];
}
return encrypted;
//System.out.println("Original IV: " + displayBytes(iv, false));
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] decrypt(String toDecrypt, byte[] keyBytes, boolean base64Encode)
{
try
{
byte[] newDecrypt = hexToByte(toDecrypt);
//toDecrypt = hexToString(toDecrypt);
if(base64Encode)
{
newDecrypt = Base64.decode(newDecrypt);
//toDecrypt = new String(Base64.decode(toDecrypt.getBytes(CHARSET)), CHARSET);
}
byte[] iv = new byte[32];
byte[] extractedMac = new byte[32];
int offset = newDecrypt.length - 32;
for(int i = 0; i < 32; i++)
{
iv[i] = newDecrypt[i];
extractedMac[i] = newDecrypt[i + offset];
}
byte[] temp = new byte[offset - 32];
for(int i = 0; i < temp.length; i++)
{
temp[i] = newDecrypt[i + 32];
}
newDecrypt = temp;
byte[] combo = new byte[newDecrypt.length + iv.length];
for(int i = 0; i < iv.length; i++)
{
combo[i] = iv[i];
}
for(int i = iv.length; i < combo.length; i++)
{
combo[i] = newDecrypt[i - iv.length];
}
byte[] mac = generateKey(new String(combo, CHARSET), new String(keyBytes, CHARSET), 1000, 32);
boolean matches = new String(extractedMac).equals(new String(mac));
if(!matches)
{
byte[] toReturn = new byte[0];
return toReturn;
}
CipherParameters cipherParameters = new ParametersWithIV(new KeyParameter(keyBytes), iv);
RijndaelEngine rijndael = new RijndaelEngine(256);
SICBlockCipher ctrMode = new SICBlockCipher(rijndael);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(ctrMode, new ZeroBytePadding());
cipher.init(true, cipherParameters);
int size = cipher.getOutputSize(newDecrypt.length);
byte[] decrypted = new byte[size];
System.out.println(displayBytes(newDecrypt, false));
System.out.println(displayBytes(decrypted, false));
int outputLength = cipher.processBytes(newDecrypt, 0, newDecrypt.length, decrypted, 0);
cipher.doFinal(decrypted, outputLength);
System.out.println(displayBytes(decrypted, false));
temp = new byte[newDecrypt.length];
for(int i = 0; i < temp.length; i++)
{
temp[i] = decrypted[i];
}
decrypted = temp;
decrypted = unserialize(new String(decrypted, CHARSET)).getBytes(CHARSET);
return decrypted;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] generateKey(String password, String salt, int blockIterations, int keyLength)
{
try
{
SHA256Digest digest = new SHA256Digest();
int hashLength = digest.getDigestSize();
long keyBlocks = (long) Math.ceil( (double) keyLength / (double) hashLength);
String derived_key = "";
//System.out.println("Number of blocks: " + keyBlocks);
for(long block = 1; block <= keyBlocks; block++)
{
byte[] initialHash = hash_hmac(salt + new String(pack(block)/*, CHARSET */), password);
byte[] compareHash = initialHash;
//System.out.println("Block: " + block);
for(int i = 1; i < blockIterations; i++)
// XOR each iterate
compareHash = hash_hmac(compareHash, password);
for(int j = 0; j < initialHash.length; j++)
{
initialHash[j] = (byte) (initialHash[j] ^ compareHash[j]);
}
}
derived_key += new String(initialHash/*, CHARSET */);
}
return derived_key.substring(0, keyLength).getBytes(CHARSET);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] generateKey(byte[] password, byte[] salt, int blockIterations, int keyLength)
{
try
{
SHA256Digest digest = new SHA256Digest();
int hashLength = digest.getDigestSize();
long keyBlocks = (long) Math.ceil( (double) keyLength / (double) hashLength);
byte[] derived_key = null;
//System.out.println("Number of blocks: " + keyBlocks);
for(long block = 1; block <= keyBlocks; block++)
{
byte[] packed = pack(block);
byte[] combined = new byte[salt.length + packed.length];
for(int i = 0; i < salt.length; i++)
{
combined[i] = salt[i];
}
for(int i = salt.length; i < combined.length; i++)
{
combined[i] = packed[i - salt.length];
}
byte[] initialHash = hash_hmac(combined, password);
byte[] compareHash = initialHash;
//System.out.println("Block: " + block);
for(int i = 1; i < blockIterations; i++)
{
// XOR each iterate
compareHash = hash_hmac(compareHash, password);
for(int j = 0; j < initialHash.length; j++)
{
initialHash[j] = (byte) (initialHash[j] ^ compareHash[j]);
}
}
if(derived_key == null)
{
derived_key = initialHash;
}
else
{
byte[] temp = new byte[derived_key.length + initialHash.length];
for(int i = 0; i < derived_key.length; i++)
{
temp[i] = derived_key[i];
}
for(int i = derived_key.length; i < temp.length; i++)
{
temp[i] = initialHash[i - derived_key.length];
}
derived_key = temp;
}
}
byte[] toReturn = new byte[keyLength];
for(int i = 0; i < toReturn.length; i++)
{
toReturn[i] = derived_key[i];
}
return toReturn;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] pack(long toPack)
{
String test = Long.toHexString(toPack);
while(test.length() < 8)
{
test = "0" + test;
}
byte[] toReturn = new byte[4];
toReturn[0] = Byte.parseByte(test.substring(0, 2));
toReturn[1] = Byte.parseByte(test.substring(2, 4));
toReturn[2] = Byte.parseByte(test.substring(4, 6));
toReturn[3] = Byte.parseByte(test.substring(6, 8));
return toReturn;
}
public String hexToString(String hex)
{
return new String(hexToByte(hex));
}
public byte[] hexToByte(String hex)
{
if(hex.length() % 2 != 0)
{
hex = "0" + hex;
}
byte[] toReturn = new byte[hex.length() / 2];
for(int i = 0; i < toReturn.length; i++)
{
toReturn[i] = Byte.parseByte(hex.substring(i * 2, (i + 1) * 2), 16);
}
//System.out.println(displayBytes(toReturn, false));
return toReturn;
}
public byte[] hash_hmac(String data, String key)
{
return hash_hmac("HmacSHA256", data, key);
}
public byte[] hash_hmac(String algorithm , String data , String key)
{
try
{
SecretKeySpec secret = new SecretKeySpec(key.getBytes(/*CHARSET*/), algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secret);
byte[] digest = mac.doFinal(data.getBytes(/*CHARSET*/));
return digest;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] hash_hmac(byte[] data, String key)
{
return hash_hmac("HmacSHA256", data, key);
}
public byte[] hash_hmac(byte[] data, byte[] key)
{
return hash_hmac("HmacSHA256", data, key);
}
public byte[] hash_hmac(String algorithm , byte[] data , byte[] key)
{
try
{
SecretKeySpec secret = new SecretKeySpec(key, algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secret);
byte[] digest = mac.doFinal(data);
return digest;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] hash_hmac(String algorithm , byte[] data , String key)
{
try
{
SecretKeySpec secret = new SecretKeySpec(key.getBytes(/*CHARSET*/), algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secret);
byte[] digest = mac.doFinal(data);
return digest;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public String displayBytes(byte[] bytes, boolean rawDisplay)
{
String toReturn = "";
if(rawDisplay)
{
toReturn = new String(bytes/*, CHARSET */);
}
else
{
for (byte b : bytes)
{
toReturn += String.format("%02x", b);
}
}
return toReturn;
}
public String toHex(String toConvert) {
if(toConvert.getBytes().length == 0)
{
return "";
}
return String.format("%04x", new BigInteger(toConvert.getBytes(/*YOUR_CHARSET?*/)));
}
/*
* This creates a string representation that should line up with PHPs serialize.
*/
public String serialize(String toSerialize)
{
return "s:" + toSerialize.length() + ":\"" + toSerialize + "\";";
}
public String unserialize(String toUnserialize)
{
System.out.println(toUnserialize);
int endIndex = toUnserialize.indexOf("\";");
while (endIndex < toUnserialize.length() && endIndex < toUnserialize.indexOf("\";", endIndex + 1))
{
endIndex = toUnserialize.indexOf("\";", endIndex + 1);
}
return toUnserialize.substring(toUnserialize.indexOf(":\"") + 2, endIndex);
}
Without reading through all the code, if an encrypt works instead of a decrypt, then you may have "decrypted" the plain text to form the cipher text, as symmetric encryption/decryption is reversable. In other words, you could use plain = encrypt(decrypt(plain)) as well as plain = decrypt(encrypt(plain)).
The only possible difference could be padding: decrypt should remove padding and encrypt should add it, so that would make a difference.
I have it working now... entire class is as follows. When using it with the PHP cryptastic, add in conversion to hexidecimal after conversion to base64.
public class Cryptastic {
public final static String CHARSET = "US-ASCII";
public byte[] encrypt(String toEncrypt, byte[] keyBytes, boolean base64Encode)
{
try
{
toEncrypt = serialize(toEncrypt);
byte[] newEncrypt = toEncrypt.getBytes(CHARSET);
BlockCipher blockCipher = new RijndaelEngine(256);
SecureRandom secureRandom = new SecureRandom();
byte[] iv = new byte[32];
secureRandom.nextBytes(iv);
CipherParameters cipherParameters = new ParametersWithIV(new KeyParameter(keyBytes), iv);
RijndaelEngine rijndael = new RijndaelEngine(256);
SICBlockCipher ctrMode = new SICBlockCipher(rijndael);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(ctrMode, new ZeroBytePadding());
cipher.init(false, cipherParameters);
int size = cipher.getOutputSize(newEncrypt.length);
byte[] padded = new byte[size];
for(int i = 0; i < newEncrypt.length; i++)
{
padded[i] = newEncrypt[i];
}
for(int i = newEncrypt.length; i < size; i++)
{
padded[i] = 0;
}
newEncrypt = padded;
byte[] encrypted = new byte[size];
int outputLength = cipher.processBytes(newEncrypt, 0, newEncrypt.length, encrypted, 0);
cipher.doFinal(encrypted, outputLength);
byte[] temp = new byte[encrypted.length + 32];
for(int i = 0; i < iv.length; i++)
{
temp[i] = iv[i];
}
for(int i = iv.length; i < temp.length; i++)
{
temp[i] = encrypted[i - iv.length];
}
encrypted = temp;
byte[] mac = generateKey(new String(encrypted, CHARSET), new String(keyBytes, CHARSET), 1000, 32);
temp = new byte[encrypted.length + mac.length];
for(int i = 0; i < encrypted.length; i++)
{
temp[i] = encrypted[i];
}
for(int i = encrypted.length; i < temp.length; i++)
{
temp[i] = mac[i - encrypted.length];
}
encrypted = temp;
if(base64Encode)
{
encrypted = Base64.encode(encrypted);
}
return encrypted;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] decrypt(String toDecrypt, byte[] keyBytes, boolean base64Encode)
{
try
{
byte[] newDecrypt = hexToByte(toDecrypt);
if(base64Encode)
{
newDecrypt = Base64.decode(newDecrypt);
}
byte[] iv = new byte[32];
byte[] extractedMac = new byte[32];
int offset = newDecrypt.length - 32;
for(int i = 0; i < 32; i++)
{
iv[i] = newDecrypt[i];
extractedMac[i] = newDecrypt[i + offset];
}
byte[] temp = new byte[offset - 32];
for(int i = 0; i < temp.length; i++)
{
temp[i] = newDecrypt[i + 32];
}
newDecrypt = temp;
byte[] combo = new byte[newDecrypt.length + iv.length];
for(int i = 0; i < iv.length; i++)
{
combo[i] = iv[i];
}
for(int i = iv.length; i < combo.length; i++)
{
combo[i] = newDecrypt[i - iv.length];
}
byte[] mac = generateKey(new String(combo, CHARSET), new String(keyBytes, CHARSET), 1000, 32);
boolean matches = new String(extractedMac).equals(new String(mac));
if(!matches)
{
byte[] toReturn = new byte[0];
return toReturn;
}
CipherParameters cipherParameters = new ParametersWithIV(new KeyParameter(keyBytes), iv);
RijndaelEngine rijndael = new RijndaelEngine(256);
SICBlockCipher ctrMode = new SICBlockCipher(rijndael);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(ctrMode, new ZeroBytePadding());
cipher.init(true, cipherParameters);
int size = cipher.getOutputSize(newDecrypt.length);
byte[] decrypted = new byte[size];
int outputLength = cipher.processBytes(newDecrypt, 0, newDecrypt.length, decrypted, 0);
cipher.doFinal(decrypted, outputLength);
temp = new byte[newDecrypt.length];
for(int i = 0; i < temp.length; i++)
{
temp[i] = decrypted[i];
}
decrypted = temp;
decrypted = unserialize(new String(decrypted, CHARSET)).getBytes(CHARSET);
return decrypted;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] generateKey(String password, String salt, int blockIterations, int keyLength)
{
try
{
SHA256Digest digest = new SHA256Digest();
int hashLength = digest.getDigestSize();
long keyBlocks = (long) Math.ceil( (double) keyLength / (double) hashLength);
String derived_key = "";
//System.out.println("Number of blocks: " + keyBlocks);
for(long block = 1; block <= keyBlocks; block++)
{
byte[] initialHash = hash_hmac(salt + new String(pack(block)/*, CHARSET */), password);
byte[] compareHash = initialHash;
//System.out.println("Block: " + block);
for(int i = 1; i < blockIterations; i++)
{
// XOR each iterate
compareHash = hash_hmac(compareHash, password);
for(int j = 0; j < initialHash.length; j++)
{
initialHash[j] = (byte) (initialHash[j] ^ compareHash[j]);
}
}
derived_key += new String(initialHash/*, CHARSET */);
}
return derived_key.substring(0, keyLength).getBytes(CHARSET);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] generateKey(byte[] password, byte[] salt, int blockIterations, int keyLength)
{
try
{
SHA256Digest digest = new SHA256Digest();
int hashLength = digest.getDigestSize();
long keyBlocks = (long) Math.ceil( (double) keyLength / (double) hashLength);
byte[] derived_key = null;
for(long block = 1; block <= keyBlocks; block++)
{
byte[] packed = pack(block);
byte[] combined = new byte[salt.length + packed.length];
for(int i = 0; i < salt.length; i++)
{
combined[i] = salt[i];
}
for(int i = salt.length; i < combined.length; i++)
{
combined[i] = packed[i - salt.length];
}
byte[] initialHash = hash_hmac(combined, password);
byte[] compareHash = initialHash;
//System.out.println("Block: " + block);
for(int i = 1; i < blockIterations; i++)
{
// XOR each iterate
compareHash = hash_hmac(compareHash, password);
for(int j = 0; j < initialHash.length; j++)
{
initialHash[j] = (byte) (initialHash[j] ^ compareHash[j]);
}
}
if(derived_key == null)
{
derived_key = initialHash;
}
else
{
byte[] temp = new byte[derived_key.length + initialHash.length];
for(int i = 0; i < derived_key.length; i++)
{
temp[i] = derived_key[i];
}
for(int i = derived_key.length; i < temp.length; i++)
{
temp[i] = initialHash[i - derived_key.length];
}
derived_key = temp;
}
}
byte[] toReturn = new byte[keyLength];
for(int i = 0; i < toReturn.length; i++)
{
toReturn[i] = derived_key[i];
}
return toReturn;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] pack(long toPack)
{
String test = Long.toHexString(toPack);
while(test.length() < 8)
{
test = "0" + test;
}
byte[] toReturn = new byte[4];
toReturn[0] = Byte.parseByte(test.substring(0, 2));
toReturn[1] = Byte.parseByte(test.substring(2, 4));
toReturn[2] = Byte.parseByte(test.substring(4, 6));
toReturn[3] = Byte.parseByte(test.substring(6, 8));
return toReturn;
}
public String hexToString(String hex)
{
return new String(hexToByte(hex));
}
public byte[] hexToByte(String hex)
{
if(hex.length() % 2 != 0)
{
hex = "0" + hex;
}
byte[] toReturn = new byte[hex.length() / 2];
for(int i = 0; i < toReturn.length; i++)
{
toReturn[i] = Byte.parseByte(hex.substring(i * 2, (i + 1) * 2), 16);
}
return toReturn;
}
public byte[] hash_hmac(String data, String key)
{
return hash_hmac("HmacSHA256", data, key);
}
public byte[] hash_hmac(String algorithm , String data , String key)
{
try
{
SecretKeySpec secret = new SecretKeySpec(key.getBytes(/*CHARSET*/), algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secret);
byte[] digest = mac.doFinal(data.getBytes(/*CHARSET*/));
return digest;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] hash_hmac(byte[] data, String key)
{
return hash_hmac("HmacSHA256", data, key);
}
public byte[] hash_hmac(byte[] data, byte[] key)
{
return hash_hmac("HmacSHA256", data, key);
}
public byte[] hash_hmac(String algorithm , byte[] data , byte[] key)
{
try
{
SecretKeySpec secret = new SecretKeySpec(key, algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secret);
byte[] digest = mac.doFinal(data);
return digest;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] hash_hmac(String algorithm , byte[] data , String key)
{
try
{
SecretKeySpec secret = new SecretKeySpec(key.getBytes(/*CHARSET*/), algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secret);
byte[] digest = mac.doFinal(data);
return digest;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public String displayBytes(byte[] bytes, boolean rawDisplay)
{
String toReturn = "";
if(rawDisplay)
{
toReturn = new String(bytes/*, CHARSET */);
}
else
{
for (byte b : bytes)
{
toReturn += String.format("%02x", b);
}
}
return toReturn;
}
public String toHex(String toConvert) {
if(toConvert.getBytes().length == 0)
{
return "";
}
return String.format("%04x", new BigInteger(toConvert.getBytes(/*YOUR_CHARSET?*/)));
}
/*
* This creates a string representation that should line up with PHPs serialize.
*/
public String serialize(String toSerialize)
{
return "s:" + toSerialize.length() + ":\"" + toSerialize + "\";";
}
public String unserialize(String toUnserialize)
{
int endIndex = toUnserialize.indexOf("\";");
while (endIndex < toUnserialize.length() && endIndex < toUnserialize.indexOf("\";", endIndex + 1))
{
endIndex = toUnserialize.indexOf("\";", endIndex + 1);
}
return toUnserialize.substring(toUnserialize.indexOf(":\"") + 2, endIndex);
}
}