To gain a better understanding of CBC and CTS im trying to impliment my own class that can encrypt and decrypt without using java's built in CTS Mode. Im using an AES wrapper class as the underlying algorithm but CTS as the mode of operation. So far i have been working on the encryption method but not sure where to go from there. I'm not really sure how to implement the swap of the blocks at end of the CTS mode.
Here is the code i have so far for my encryption method (and dont worry about the AES class it works 100%):
static byte[] encrypt(byte[] ptBytes, javax.crypto.SecretKey key, byte[] IV){
byte [] ct;
byte [] pt;
byte [] ptBlock, ctBlock;
//pad the array to proper length
pt = Arrays.copyOf(ptBytes, (int) (Math.ceil( ( ptBytes.length )/16)*16) );
//ctBlock = one block of cipher text
ctBlock = new byte [16];
//make ct the length of the padded pt
ct = new byte [pt.length];
//do the encryption
//i is for the current block of plain / cipher text we are on
for( int i = 1; i < (int) ((Math.ceil( ( ptBytes.length )/16)+1)); i++){
if( i == 1 ){
//make ptBlock the first block of the entire plain text
ptBlock = Arrays.copyOfRange(pt, 0, (i*16)-1);
//since i = 1 do the XOR to get new plain text with IV
for (int j = 0; j < ptBlock.length - 1; j++){
ptBlock[j] = (byte)(ptBlock[j] ^ IV[j]);
}
//now time to do the encryption between the current block of plain text and the key
try {
ctBlock = AES.encrypt(ptBlock, key);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//now put the cipher text block we just got into the final cipher text array
for( int k = 0; k < ctBlock.length; k++){
ct[k] = ctBlock[k];
}
}
else{
//make ptBlock the current number block of entire plain text
ptBlock = Arrays.copyOfRange(pt, (i-1)*16, (i*16)-1);
//now XOR the plain text block with the prior cipher text block
for(int j = 0; j < ptBlock.length - 1; j++){
ptBlock[i] = (byte) (ptBlock[j] ^ ctBlock[j]);
}
//now time to do the encryption between the current block of plain text and the key
try {
ctBlock = AES.encrypt(ptBlock, key);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//now put the cipher text block we just got into the final cipher text array
for( int k = (i-1)*16; k < (i*16)-1; k++){
ct[k] = ctBlock[k-16];
}
}
}
return ct;
}
Just if anyone could give some insight into how to finish this method up that would be great because i still am learning the ins and outs of CBC/CTS
Thanks!
Related
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!!!
(我只加了&就成功拉,你的代碼沒問題,只是參數要加&而已)
I am trying to reuse an AES implementation with Initialization Vector. So far I am only implementing the part where data is being encrypted on the android application and being decrypted on the php server. However, the algorithm has a major loophole, that the Initialization Vector is constant, which I just recently found out is a major security flaw. Unfortunately I have already implemented it on every single activity of my application and all scripts on the server side.
I wanted to know if there was a way to modify this code so that the initialization vector is randomized, and some way to send that vector to the server (or vice versa), so that every time the message is encrypted the pattern keeps changing. Here are my codes for Android and PHP:
Android:
package com.fyp.merchantapp;
// This file and its contents have been taken from http://www.androidsnippets.com/encrypt-decrypt-between-android-and-php.html
//Ownership has been acknowledged
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 {
static char[] HEX_CHARS = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
private String iv = "MyNameIsHamza100";//(IV)
private IvParameterSpec ivspec;
private SecretKeySpec keyspec;
private Cipher cipher;
private String SecretKey = "MyNameIsBilal100";//(SECRETKEY)
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));
//Remove trailing zeroes
if( decrypted.length > 0)
{
int trim = 0;
for( int i = decrypted.length - 1; i >= 0; i-- ) if( decrypted[i] == 0 ) trim++;
if( trim > 0 )
{
byte[] newArray = new byte[decrypted.length - trim];
System.arraycopy(decrypted, 0, newArray, 0, decrypted.length - trim);
decrypted = newArray;
}
}
} catch (Exception e)
{
throw new Exception("[decrypt] " + e.getMessage());
}
return decrypted;
}
public static String bytesToHex(byte[] buf)
{
char[] chars = new char[2 * buf.length];
for (int i = 0; i < buf.length; ++i)
{
chars[2 * i] = HEX_CHARS[(buf[i] & 0xF0) >>> 4];
chars[2 * i + 1] = HEX_CHARS[buf[i] & 0x0F];
}
return new String(chars);
}
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 = 0;
int size = 16;
int x = source.length() % size;
int padLength = size - x;
for (int i = 0; i < padLength; i++)
{
source += paddingChar;
}
return source;
}
}
PHP:
<?php
class MCrypt
{
private $iv = 'MyNameIsHamza100'; #Same as in JAVA
private $key = 'MyNameIsBilal100'; #Same as in JAVA
function __construct()
{
}
/**
* #param string $str
* #param bool $isBinary whether to encrypt as binary or not. Default is: false
* #return string Encrypted data
*/
function encrypt($str, $isBinary = false)
{
$iv = $this->iv;
$str = $isBinary ? $str : utf8_decode($str);
$td = mcrypt_module_open('rijndael-128', ' ', 'cbc', $iv);
mcrypt_generic_init($td, $this->key, $iv);
$encrypted = mcrypt_generic($td, $str);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $isBinary ? $encrypted : bin2hex($encrypted);
}
/**
* #param string $code
* #param bool $isBinary whether to decrypt as binary or not. Default is: false
* #return string Decrypted data
*/
function decrypt($code, $isBinary = false)
{
$code = $isBinary ? $code : $this->hex2bin($code);
$iv = $this->iv;
$td = mcrypt_module_open('rijndael-128', ' ', 'cbc', $iv);
mcrypt_generic_init($td, $this->key, $iv);
$decrypted = mdecrypt_generic($td, $code);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $isBinary ? trim($decrypted) : utf8_encode(trim($decrypted));
}
protected function hex2bin($hexdata)
{
$bindata = '';
for ($i = 0; $i < strlen($hexdata); $i += 2) {
$bindata .= chr(hexdec(substr($hexdata, $i, 2)));
}
return $bindata;
}
}
?>
To directly answer your question: you can simply generate a random IV and prefix it to the ciphertext. You need to do this before encoding the ciphertext to hexadecimals. Then during decryption first decode, then "remove" the IV bytes, initialize the IV and finally decrypt the ciphertext to obtain the plaintext.
Note that the IV will always be 16 bytes for AES in CBC mode, so there is no direct need to include the IV length anywhere. I used quotes around "remove" as both IvParameterSpec as Cipher.doFinal accept buffers with offset and length; there is no need to copy the bytes to different arrays.
Notes:
keys should not be strings; lookup PBKDF's such as PBKDF2 to derive a key from a password or pass phrase;
CBC is generally vulnerable to padding oracle attacks; however, by keeping to PHP's zero padding you may have avoided attacks by accident;
CBC doesn't provide integrity protection, so note that adversaries may change the ciphertext without decryption failing;
if the underlying code that uses the text generates errors then you may be vulnerable to plaintext oracle attacks (padding oracle attacks are only part of the larger group of plaintext oracles);
your Java code is unbalanced; the encrypt and decrypt mode should either perform hex encoding / decoding or they should not;
the exception handling is of course not good (although that may be just for the example);
String#getBytes() will use UTF-8 on Android, but it may use Windows-1252 on Java SE on Windows, so this is prone to generating the wrong key if you're not careful - always define the character set to use.
To use a shared secret to communicate, try TLS in pre-shared secret mode, defined by one of the PSK_ cipher suites.
I have created the following python code
import base64
from django.conf import settings
from Crypto.Cipher import AES
BS = 16
def pad(s):
return s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
def unpad(s):
return s[0:-s[-1]]
class AESCipher:
def __init__(self):
self.key = settings.SECRET_KEY
def encrypt(self, raw):
raw = pad(raw)
iv = settings.SECRET_IV.encode('utf-8')
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return base64.b64encode(cipher.encrypt(raw))
def decrypt(self, enc):
enc = base64.b64decode(enc)
iv = settings.SECRET_IV.encode('utf-8')
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return unpad(cipher.decrypt(enc))
def encryptstring(self, raw):
raw = self.encrypt(raw)
raw = raw.decode('utf-8')
return raw
def decryptstring(self, raw):
raw = raw.encode('utf-8')
raw = self.decrypt(raw)
raw = raw.decode('utf-8')
return raw
This code returns a base64 encrypted string (i.e. VgRaS+J3MSmguabaf+9fJw==).
I have also created a java function, that should create the same thing, but it doesn't match.
public void login() {
SecretKeySpec keySpec;
IvParameterSpec ivSpec;
Cipher cipher;
String key = "";
String iv = "";
try {
keySpec = new SecretKeySpec(key.getBytes(), "AES");
ivSpec = new IvParameterSpec(iv.getBytes());
cipher = Cipher.getInstance("AES/CBC/NoPadding");
String test = "Test";
String newString = "";
char paddingChar = ' ';
int size = 16;
int x = test.length() % size;
int padLength = size - x;
for (int i = 0; i < padLength; i++) {
newString += paddingChar;
// test += paddingChar;
}
newString += test;
byte[] res;
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
res = cipher.doFinal(newString.getBytes());
for(int i = 0; i < res.length; i++) {
System.out.print(res[i] + ", ");
}
System.out.println("");
System.out.println(bytesToHex(res));
String base = Base64.encodeToString(res, Base64.DEFAULT);
System.out.println(base);
// TODO: VgRaS+J3MSmguabaf+9fJw==
// OyuUHNsBQ3Zuy4UGY4fUdQ==
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
}
The result I get there is 2mdRXydTCAYG+Tp0kE/NoQ==. It looks similar, but it isn't. I have checked the keys, they are the same. I have swapped them around, to make sure that wasn't the problem either. I have tried different cipher modes (AES/CBC/ISO10126Padding and AES/CBC/PKCS5Padding) both without result. I have tried to do it with plain AES, no success either. I tried to get AES_128/CBC/NoPadding and AES_256/CBC/NoPadding to work, but for some reason it tells me java.security.NoSuchAlgorithmException: No provider found for AES_256/CBC/NoPadding.
I am lost, I hope someone can help! Thanks in advance!
As JamesKPolk pointed out, the padding was wrong. I have solved this by doing the following:
Python has the following
def pad(s):
return s.ljust(16, '0')
Java has the following
char paddingChar = '0';
I'm decrypting a regular text file and encountering an issue I cant solve,
My code works like this,
I receive a txt file with letters,numbers and the signs + and / (which is Radix64)
I then read 12 chars from the file, convert them into a string, and then using base64.decoder to decode the text into an 8 byte array.
Using system.out.print on both the byte array and on the string I build shows me that the reading was correct and I got what I needed from the file.
Now I shift the bytes a few times to the right or left and want to write the byte array to a new file which is the decrypted message.
I'm using FileOutputStream to write to a new file, now comes the problem, I open the file and its all Chinese letters.
I have no clue how is that even possible since the only thing I do is write bytes to a file.
I tried to find information regarding this subject without any success, only related topic was python/ruby related and was stating that its a UTF-8/UTF-16 problem but no answers to how to fix it.
Any help would be appreciated, and if posting parts of my code will help please let me know what exactly is needed.
private static void Decryption() {
InputStream byteReader = null;
FileOutputStream fop = null;
int byteByByte = 0;
char[] radixToByte = new char[12];
byte[] block = new byte[8];
byte[] decryptedBlock = new byte[8];
long key = 0;
//the file which will contain the plain text will be p.txt in the same directory c.txt is
try {
fop = new FileOutputStream(new File(fileName.substring(0, fileName.length()-5)+"p.txt"));
} catch (FileNotFoundException e) {
System.out.println("File was not found");
e.printStackTrace();
}
//open key file and read the key.
try {
byteReader = new FileInputStream(keyFileName);
} catch (FileNotFoundException e) {
System.out.println("File was not found");
System.exit(0);
}
//reading 56 bits in radix format and building the key accordingly
char[] keyByteArray = new char[12];
for(int k = 0; k < 12; k++){
try {
byteByByte = byteReader.read();
} catch (IOException e) {
e.printStackTrace();
}
keyByteArray[k] = (char) byteByByte;
}
Base64.Decoder decoder = Base64.getDecoder();
byte[] decodedByteArray = decoder.decode(new String(keyByteArray));
for(int k = 0; k < 7; k++){
key <<= 8;
key |= (decodedByteArray[k] & 0x00000000000000FF);
}
//open cipher text to decrypt.
try {
byteReader = new FileInputStream(fileName);
} catch (FileNotFoundException e) {
System.out.println("File was not found");
System.exit(0);
}
//while haven't reached end of cipher text message keep reading byte by byte and decrypting
//them block by block (each block 64 bits).
while(isFileReadingFinished == false){
for(int i = 0; i < 12; i++){
try {
byteByByte = byteReader.read();
} catch (IOException e) {
e.printStackTrace();
}
if(byteByByte == -1){
isFileReadingFinished = true;
break;
}
radixToByte[i] = (char)byteByByte;
}
//this is the block after radix but still decrypted so we will save it for CBC
block = decoder.decode(new String(radixToByte));
//encrypt via feistel
decryptedBlock = feistel(block, key);
//after decryption we still need to xor with previous encrypted data or IV.
for(int i = 0; i < 8; i++){
decryptedBlock[i] = (byte) (decryptedBlock[i] ^ initializationVector[i]);
}
//next decrypted text will need to be xored with the current encrypted text after decryption.
for(int i = 0; i < 8; i++){
initializationVector[i] = block[i];
}
try {
fop.write(decryptedBlock);
fop.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
}
try {
fop.close();
} catch (IOException e) {
e.printStackTrace();
}
}
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.