PBEKeySpec with byte array argument instead of ASCII - java

I would like to know if there is a way to use PBEKeySpec with a byte array argument.
Please find a link to the documentation below:
http://docs.oracle.com/javase/1.7/docs/api/javax/crypto/spec/PBEKeySpec.html)

Here below is my solution: I got it googling around. Please consider I have to internally copy the password and the salt since they have another format when they come from the outside, but the result is the same. It seems it works and solves the problem of having a password as byte[] and not as char[] (it was driving me crazy)
I hope it helps!
Cheers, Soosta
public class Pbkdf2 {
public Pbkdf2() {
}
public void GenerateKey(final byte[] masterPassword, int masterPasswordLen,
final byte[] salt, int saltLen,
int iterationCount, int requestedKeyLen,
byte[] generatedKey) {
byte[] masterPasswordInternal = new byte[masterPasswordLen];
System.arraycopy(masterPassword, 0, masterPasswordInternal, 0, masterPasswordLen);
byte[] saltInternal = new byte[saltLen];
System.arraycopy(salt, 0, saltInternal, 0, saltLen);
SecretKeySpec keyspec = new SecretKeySpec(masterPasswordInternal, "HmacSHA1");
Mac prf = null;
try {
prf = Mac.getInstance("HmacSHA1");
prf.init(keyspec);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
int hLen = prf.getMacLength(); // 20 for SHA1
int l = Math.max(requestedKeyLen, hLen); // 1 for 128bit (16-byte) keys
int r = requestedKeyLen - (l - 1) * hLen; // 16 for 128bit (16-byte) keys
byte T[] = new byte[l * hLen];
int ti_offset = 0;
for (int i = 1; i <= l; i++) {
F(T, ti_offset, prf, saltInternal, iterationCount, i);
ti_offset += hLen;
}
System.arraycopy(T, 0, generatedKey, 0, requestedKeyLen);
}
private static void F(byte[] dest, int offset, Mac prf, byte[] S, int c, int blockIndex) {
final int hLen = prf.getMacLength();
byte U_r[] = new byte[hLen];
// U0 = S || INT (i);
byte U_i[] = new byte[S.length + 4];
System.arraycopy(S, 0, U_i, 0, S.length);
INT(U_i, S.length, blockIndex);
for (int i = 0; i < c; i++) {
U_i = prf.doFinal(U_i);
xor(U_r, U_i);
}
System.arraycopy(U_r, 0, dest, offset, hLen);
}
private static void xor(byte[] dest, byte[] src) {
for (int i = 0; i < dest.length; i++) {
dest[i] ^= src[i];
}
}
private static void INT(byte[] dest, int offset, int i) {
dest[offset + 0] = (byte) (i / (256 * 256 * 256));
dest[offset + 1] = (byte) (i / (256 * 256));
dest[offset + 2] = (byte) (i / (256));
dest[offset + 3] = (byte) (i);
}
}

I had to implement a two-phase pbkdf2 derivation (so the second pbkdf2 had bytes from the first as input). I ended up using BouncyCastle because I just couldn't get the byte array to char array gymnastics to work. Credit to Pasi from this other question: Reliable implementation of PBKDF2-HMAC-SHA256 for JAVA
import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.GeneralDigest;
import org.bouncycastle.crypto.params.KeyParameter;
GeneraDigest algorithm = new SHA256Digest();
PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(algorithm);
gen.init(passwordBytes, salt, iterations);
byte[] dk = ((KeyParameter) gen.generateDerivedParameters(256)).getKey();

As the Java PKCS#5 KeyFactory has been specified to only use the lower 8 bits of the characters in the PBEKeySpec, you should be able to convert your byte array into a (16 bit) character array without issue. Just copy the value of each byte into the character array and you should be set.
Just to be sure, I would perform charArray[i] = byteArray[i] & 0xFF as assignment statement, otherwise you would get very high valued characters.
It's an ugly workaround, but I don't see any reason why it should not work.
Note that the above assumes Latin / Windows 1252 compatible encoding for values 0x80 and over. If you allow code points of 0x80 to 0xFF then you cannot use UTF-8 (or UTF-16 of course) as encoding.

I was able to do this using a 3rd party library and extending one of their classes.
Here is the RFC 2898 implementation library that I used:
http://www.rtner.de/software/PBKDF2.html
My code:
import de.rtner.security.auth.spi.PBKDF2Engine;
import de.rtner.security.auth.spi.PBKDF2Parameters;
public class PBKDF2Utils {
private static class PBKDF2EngineWithBinaryPassword extends PBKDF2Engine {
private PBKDF2EngineWithBinaryPassword(PBKDF2Parameters parameters) {
super(parameters);
}
public byte[] deriveKey(byte[] inputPassword, int dkLen) {
this.assertPRF(inputPassword);
return this.PBKDF2(prf, parameters.getSalt(), parameters.getIterationCount(), dkLen);
}
}
public static byte[] deriveKey(
byte[] password,
byte[] salt,
int iterationCount,
int dkLen) {
PBKDF2Parameters parameters = new PBKDF2Parameters("HmacSHA1", null, salt, iterationCount);
PBKDF2EngineWithBinaryPassword engine = new PBKDF2EngineWithBinaryPassword(parameters);
return engine.deriveKey(password, dkLen);
}
}

Related

Java 256-bit AES Encryption

I need to implement 256 bit AES encryption for cash flow i have c# answer but the answer is not the same,for a newbie, I am not sure if my direction is correct.
this is my code
public static void main(String[] args) {
String key = "12345678901234567890123456789012";
String hashIv = "1234567890123456";
String value = "MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest";
String result = encrypt(key, hashIv, value);
System.out.println(result);
System.out.println();
String sha256 = encrySha256("HashKey=" + key + "&" + result + "&HashIV=" + hashIv);
System.out.println(sha256.trim());
}
public static String encrypt(String hashKey, String hashIv, String text) {
try {
SecretKeySpec skeySpec = new SecretKeySpec(hashKey.getBytes("UTF-8"), "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(hashIv.getBytes("UTF-8"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal((text.getBytes("UTF-8")));
String test = bytesToHex(encrypted);
return test.toLowerCase();
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
public static String bytesToHex(byte[] bytes) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
public static String encrySha256(String value) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(value.getBytes());
byte byteBuffer[] = messageDigest.digest();
StringBuffer strHexString = new StringBuffer();
for (int i = 0; i < byteBuffer.length; i++) {
String hex = Integer.toHexString(0xff & byteBuffer[i]);
if (hex.length() == 1) {
strHexString.append('0');
}
strHexString.append(hex);
}
return strHexString.toString().toUpperCase();
} catch (Exception e) {
}
return null;
}
sample encrypt answer :
ff91c8aa01379e4de621a44e5f11f72e4d25bdb1a18242db6cef9ef07d80b0165e476fd1d
9acaa53170272c82d122961e1a0700a7427cfa1cf90db7f6d6593bbc93102a4d4b9b66d9
974c13c31a7ab4bba1d4e0790f0cbbbd7ad64c6d3c8012a601ceaa808bff70f94a8efa5a4f
984b9d41304ffd879612177c622f75f4214fa
encryptSha256 answer : EA0A6CC37F40C1EA5692E7CBB8AE097653DF3E91365E6A9CD7E91312413C7BB8
this is c# code and this is sample data
[MerchantID] => 3430112 [RespondType] => JSON [TimeStamp] => 1485232229
[Version] => 1.4 [MerchantOrderNo] => S_1485232229 [Amt] => 40 [ItemDesc] =>
UnitTest
public string EncryptAES256(string source)//加密
{
string sSecretKey = "12345678901234567890123456789012";
string iv = "1234567890123456";
byte[] sourceBytes =
AddPKCS7Padding(Encoding.UTF8.GetBytes(source), 32);
var aes = new RijndaelManaged();
aes.Key = Encoding.UTF8.GetBytes(sSecretKey);
aes.IV = Encoding.UTF8.GetBytes(iv);
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.None;
ICryptoTransform transform = aes.CreateEncryptor();
return ByteArrayToHex(transform.TransformFinalBlock(sourceBytes, 0,
sourceBytes.Length)).ToLower();
}
private static byte[] AddPKCS7Padding(byte[] data, int iBlockSize)
{
int iLength = data.Length;
byte cPadding = (byte)(iBlockSize - (iLength % iBlockSize));
var output = new byte[iLength + cPadding];
Buffer.BlockCopy(data, 0, output, 0, iLength);
for (var i = iLength; i < output.Length; i++)
output[i] = (byte)cPadding;
return output;
}
private static string ByteArrayToHex(byte[] barray)
{
char[] c = new char[barray.Length * 2];
byte b;
for (int i = 0; i < barray.Length; ++i)
{
b = ((byte)(barray[i] >> 4));
c[i * 2] = (char)(b > 9 ? b + 0x37 : b + 0x30);
b = ((byte)(barray[i] & 0xF));
c[i * 2 + 1] = (char)(b > 9 ? b + 0x37 : b + 0x30);
}
return new string(c);
}
The reason for the different encrypted data is that you compare different plain texts. In your Java code you encrypt the plain text
MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest
and you compare the encrypted data with your reference data
ff91c8aa01379e4de621a44e5f11f72e4d25bdb1a18242db6cef9ef07d80b0165e476fd1d9acaa53170272c82d122961e1a0700a7427cfa1cf90db7f6d6593bbc93102a4d4b9b66d9974c13c31a7ab4bba1d4e0790f0cbbbd7ad64c6d3c8012a601ceaa808bff70f94a8efa5a4f984b9d41304ffd879612177c622f75f4214fa
However, these reference data correspond to a different plain text. The latter you can easily derive by decrypting the reference data with the C# DecryptAES256-method which provides
MerchantID=3430112&RespondType=JSON&TimeStamp=1485232229&Version=1.4&MerchantOrderNo=S_1485232229&Amt=40&ItemDesc=UnitTest
Here, in contrast to the plain text in your Java code, a &-delimiter is used.
If you use the same plain text the Java encrypt- and the C# EncryptAES256-method provide the same encrypted data (same key, IV and padding supposed; for the latter see EDIT-section).
In the following testcase the plain text from your Java code is used:
encrypt("12345678901234567890123456789012", "1234567890123456", "MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest")
and
EncryptAES256("MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest")
both provide the encrypted data:
ff91c8aa01379e4de621a44e5f11f72ef45b7b9f9663d386da51af13f7f3b8f2b1ed4a3b7ac6b7783402193ea1d766e3046b6acf612d62568ccdbc475e5a14d114273735b069464dcc8281f4e5bf8486eb97d31602c3fe79cfe7140d2848413edad9d96fabf54d103f3d7a9b401c83fa5e4f17b10a280df10b3d61f23e69bbb8
which (as expected) differs from your reference data (with the exception of the first block).
EDIT
There is a second issue concerning the padding: Your C# EncryptAES256-method uses a custom padding provided by the C# AddPKCS7Padding-method which pads to a multiple of 32 bytes.
In contrast, your Java encrypt-method uses PKCS5Padding which pads to a multiple of 16 bytes.
Thus, the encrypted data of the Java encrypt- and the C# EncryptAES256-method differ if the length of the plain text is between 16 * n byte and 16 * (n + 1) - 1 byte with even n (0,2,4,...).
For odd n (1,3,5,...) the encrypted data are identical. In the example above the byte array of the plain text has 116 bytes that is n = 7 (112 <= 116 <= 127) and therefore the encrypted data are the same.
If the Java encrypt-method should use the same padding as the C# EncryptAES256-method you additionally have to implement an analogous Java-method e.g.:
private static byte[] addPKCS7Padding(byte[] data, int iBlockSize)
{
int iLength = data.length;
byte cPadding = (byte)(iBlockSize - (iLength % iBlockSize));
byte[] output = new byte[iLength + cPadding];
System.arraycopy(data, 0, output, 0, iLength);
for (int i = iLength; i < output.length; i++)
output[i] = (byte)cPadding;
return output;
}
and in the Java encrypt-method you have to replace:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
with
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
and also
byte[] encrypted = cipher.doFinal(text.getBytes("UTF-8"));
with
byte[] encrypted = cipher.doFinal(addPKCS7Padding(text.getBytes("UTF-8"), 32));
before:
MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest
After:
MerchantID=3430112&RespondType=JSON&TimeStamp=1485232229&Version=1.4&MerchantOrderNo=S_1485232229&Amt=40&ItemDesc=UnitTest
I only add "&" with each parameter, it's work!!!!
try it!!!
(我只加了&就成功拉,你的代碼沒問題,只是參數要加&而已)

Google OTP Generation Java

I am currently trying to recreate a Google One Time Password generator. I use a shared secret generated when I setup Google Authenticator.
I tried looking into the Google Authenticator sources and all around the internet really and I find a lot of similarities with my code but I can't really find where i'm wrong.
The first part seems correct. As for the hmac, I don't think I could mess up here but I might be wrong. The truncating part is still a bit blurry for me and I tried a lot of different implementations but I just cannot get a working OTP. (I'm using Google Authenticator to compare the results)
private String truncateHash(byte[] hash) {
int offset = hash[hash.length - 1] & 0xF;
long truncatedHash = 0;
for (int i = 0; i < 4; ++i) {
truncatedHash <<= 8;
truncatedHash |= (hash[offset + i] & 0xFF);
}
truncatedHash &= 0x7FFFFFFF;
truncatedHash %= 1000000;
int code = (int) truncatedHash;
String result = Integer.toString(code);
for (int i = result.length(); i < 6; i++) {
result = "0" + result;
}
return result;
}
private byte[] hmacSha1(byte[] value, byte[] keyBytes) {
try {
Mac mac = HmacUtils.getHmacSha1(keyBytes);
byte[] rawHmac = mac.doFinal(value);
return new Hex().encode(rawHmac);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String GoogleAuthenticatorCode(String secret) throws UnsupportedEncodingException {
Base32 base = new Base32();
byte[] key = base.decode(secret);
//Update from Andrew Rueckert's response
long value = new Date().getTime() / TimeUnit.SECONDS.toMillis(30);
byte[] data = new byte[8];
for (int i = 8; i-- > 0; value >>>= 8) {
data[i] = (byte) value;
}
//
System.out.println("Time remaining : " + new Date().getTime() / 1000 % 30);
byte[] hash = hmacSha1(data, key);
return truncateHash(hash);
}
UPDATE :
I tried copying and pasting the code from Andrew Rueckert's response's link as well as this one https://github.com/wstrange/GoogleAuth/blob/master/src/main/java/com/warrenstrange/googleauth/GoogleAuthenticator.java and the one from RFC 4226. Neither of these give me a correct OTP
Can anyone enlighten me please?
Your byte value[] needs to be the byte representation of the time as a long, and it looks like it's currently the byte representation of that number as a String of digit characters. Instead of
Double time = floor(new Date().getTime() / 1000 / 30);
String message = String.valueOf(time.intValue());
byte[] value = message.getBytes("UTF-8");
byte[] hash = hmacSha1(value, key);
You'd want something like:
// decimal truncation is free when dealing with int/long
long value = new Date().getTime() / 1000 / 30;
byte[] data = new byte[8];
for (int i = 8; i-- > 0; value >>>= 8) {
data[i] = (byte) value;
}
byte[] hash = hmacSha1(data, key);
I managed to get a Google TOTP implementation set up by following this guide, if you want one more resource to look into.
I solved my problem so I thought I would post it there in case someone needs it.
It was partialy due to the Base32 class I was using which didn't return a correct key. The truncating wasn't correct either.
It's compatible with Google Authenticator app.
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class Authentication {
Authentication() {};
private String truncateHash(byte[] hash) {
String hashString = new String(hash);
int offset = Integer.parseInt(hashString.substring(hashString.length() - 1, hashString.length()), 16);
String truncatedHash = hashString.substring(offset * 2, offset * 2 + 8);
int val = Integer.parseUnsignedInt(truncatedHash, 16) & 0x7FFFFFFF;
String finalHash = String.valueOf(val);
finalHash = finalHash.substring(finalHash.length() - 6, finalHash.length());
return finalHash;
}
private byte[] hmacSha1(byte[] value, byte[] keyBytes) {
SecretKeySpec signKey = new SecretKeySpec(keyBytes, "HmacSHA1");
try {
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signKey);
byte[] rawHmac = mac.doFinal(value);
return new Hex().encode(rawHmac);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String GoogleAuthenticatorCode(String secret) throws Exception {
if (secret == null || secret == "") {
throw new Exception("Secret key does not exist.");
}
long value = new Date().getTime() / TimeUnit.SECONDS.toMillis(30);
Base32 base = new Base32(Base32.Alphabet.BASE32, false, true);
byte[] key = base.fromString(secret);
byte[] data = new byte[8];
for (int i = 8; i-- > 0; value >>>= 8) {
data[i] = (byte) value;
}
byte[] hash = hmacSha1(data, key);
return truncateHash(hash);
}
}
The Base32 I used is available here if needed along with the rest of the project : https://github.com/Poncholay/OTPGenerator/blob/master/src/main/java/com/requireris/app/web/rest/Base32.java

how to base64 encode an unsigned byte array which is actually a int[]

I have a problem to communicating between C# and JAVA. I have to hash a value in my program with SHA1 in JAVA. The problem is, computing hash in JAVA results a byte[] (so do C#, but:) byte type in JAVA is signed, while it's unsigned in C#. So I have to get rid of extra bits in JAVA (the C# side can not be touched). Here is what I'm doing:
private static int[] Hash(byte[] plainBytes, byte[] saltBytes)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
byte[] sourceBytes = new byte[plainBytes.length + saltBytes.length];
for (int i = 0, il = plainBytes.length; i < il; i++)
sourceBytes[i] = plainBytes[i];
for (int i = 0, il = saltBytes.length, pil = plainBytes.length; i < il; i++)
sourceBytes[pil + i] = saltBytes[i];
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
byte[] resultBytes = digest.digest(sourceBytes);
int[] result = new int[resultBytes.length];
for (int i = 0, il = resultBytes.length; i < il; i++)
result[i] = ((int) resultBytes[i]) & 255;
return result;
}
It gives me the correct array. But, the problem is base64 encoding the result. How can I do that without falling in signed byte trap again? I mean how to complete this snippet:
var resultArray = Hash(someSource, someSalt);
var resultBase64EncodedString = HOW_TO_BASE64_ENCODE_HERE(resultArray);
Thanks in advance.
Base64 encoding your resultBytes array with
String base64EncodedString = DatatypeConverter.printBase64Binary(resultBytes);
should give you the same base64 coded string as you get in C# with
SHA1 sha1 = SHA1.Create();
byte[] currentHash = new byte[0];
currentHash = sha1.ComputeHash(sourceBytes);
String base64EncodedString = Convert.ToBase64String(currentHash);

Android MD5 issue calculating MD5, missing characters

I've been developing an Android App and in certain part of the app I need to calculate the MD5 of a certain string. I've been using the following code, but every now and then the output string if the byte it has to convert to String is lower than 10, then it will miss a 0 in the two byte representation:
MessageDigest di = java.security.MessageDigest.getInstance("MD5");
di.update(cadena.getBytes());
byte mdi[] = di.digest();
StringBuffer md5= new StringBuffer();
for (byte b : mdi) {
md5.append(Integer.toHexString(0xFF & b));
}
For example, if I pass the string 109370 the MD5 it will have to return is 932ff0696b0434d7a83e1ff84fe298c5 but instead it calculates the 932ff0696b434d7a83e1ff84fe298c5.
That's because the byte array has a 4 and Integer.toHexString() is returning only 1 char array instead of two.
Any thought about how can I handle this?
Thanks!
below is the code that i am using:
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Encode {
private static String convertedToHex(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++) {
int halfOfByte = (data[i] >>> 4) & 0x0F;
int twoHalfBytes = 0;
do {
if ((0 <= halfOfByte) && (halfOfByte <= 9)) {
buf.append((char) ('0' + halfOfByte));
} else {
buf.append((char) ('a' + (halfOfByte - 10)));
}
halfOfByte = data[i] & 0x0F;
} while (twoHalfBytes++ < 1);
}
return buf.toString();
}
public static String MD5(String text) throws NoSuchAlgorithmException,
UnsupportedEncodingException {
MessageDigest md;
md = MessageDigest.getInstance("MD5");
byte[] md5 = new byte[64];
md.update(text.getBytes("iso-8859-1"), 0, text.length());
md5 = md.digest();
return convertedToHex(md5);
}
}
and use it by this way:
MD5Encode.MD5("your string here")
hope this will help you :)
You can use a java.util.Formatter:
Formatter fmt = new Formatter(md5);
for (byte b : mdi) {
fmt.format("%02x", b&0xff);
}
fmt.close();
Use this:
public String calculateMD5(String string) {
StringBuilder result = new StringBuilder();
try {
MessageDigest m = MessageDigest.getInstance("MD5");
m.update(string.getBytes("UTF8"));
byte s[] = m.digest();
for (int i = 0; i < s.length; i++) {
result.append(Integer.toHexString((0x000000ff & s[i]) | 0xffffff00).substring(6));
}
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("Password hash is unsupported by device android implementation.", e);
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("Password hash is unsupported by device android implementation.", e);
}
return result.toString();
}

How can I add a time stamp to the Blowfish cryptographic algorithm in Java?

I'm running Java in Eclipse, fyi.
I have plaintext which is encrypted using Blowfish and decrypted on another end. I want to add a time stamp, such that the encrypted text is different each time for the same plaintext.
How can I add the a time stamp to the blowfish algorithm in Java, such that I can decrypt it on another end?
Thank you.
Here is my encryption code:
import BlowfishJ.*;
public class EncryptBlowFishTest {
/**
* #param args
*/
public static void main(String[] args) {
long CBCIV = 0x0x765904567324590L;
String pwd = "1234567890";
int pwdLength = password.length();
// generate key
byte[] testkey = new byte[5];
for (int i = 0; i < testkey.length; i++)
testkey[i] = (byte) (i + 1);
BlowfishCBC blowfishcbc = new BlowfishCBC(testkey, 0, testkey.length, CBCIV);
byte[] tempBuffer = pwd.getBytes();
// align to the next 8 byte border
byte[] msgBuffer;
int n = pwdLength & 7;
if (n != 0) {
msgBuffer = new byte[(pwdLength & (~7)) + 8];
System.arraycopy(tempBuffer, 0, msgBuffer, 0, pwdLength);
for (int i = pwdLength; i < msgBuffer.length; i++)
msgBuffer[i] = 0;
}
else {
msgBuffer = new byte[pwdLength];
System.arraycopy(tempBuffer, 0, msgBuffer, 0, pwdLength);
}
byte[] showCBCIV = new byte[BlowfishCBC.BLOCKSIZE];
blowfishcbc.getCBCIV(showCBCIV, 0);
blowfishcbc.encrypt(msgBuffer, 0, msgBuffer, 0, msgBuffer.length);
String encryptedPwd = BinConverter.bytesToBinHex(msgBuffer);
System.out.println(encryptedPwd);
}
}
Make the time stamp the first part of your plain-text, then encrypt everything.
Use a random IV, instead. Just generate a random sequence of bytes of the appropriate length and use it as your IV.
Send the IV unencrypted, among with your encrypted message.
Using a random IV is a standard practice (PKCS#5).
Similarly to zmbq you could simply append System.currentTimeMillis() to the text before encrypting. Then when decrypting remove the long. You may want to use a delimiter to make it easier to remove.

Categories