Decrypting hyperlocal with Signature Mismatch (Google RTB) - java

Following Google's advice here and using their code as a guide. I've tried using their encrypted hyperlocal string to test the decryption method that I wrote (most of it from Google though as my own attempts at writing such a method caused me much headache).
I'm getting Signature Mismatch for some reason even though I'm providing the proper integrity and encryption keys and I'm using the byte array that they provided in their example decryption (lower down Google's RTB decrypt hyperlocal page).
I have the code here:
package anon.bidder.adx;
import java.io.ByteArrayOutputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
import org.apache.log4j.Logger;
public class AdxBidRequestDecryptor {
private static final int INITIALIZATION_VECTOR_SIZE = 16;
private static final int SIGNATURE_SIZE = 4;
private static final int BLOCK_SIZE = 20;
public static class DecrypterException extends Exception {
public DecrypterException(String message) {
super(message);
}
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
public static void main(String args[]){
byte[] ciphertext = hexStringToByteArray("E2014EA201246E6F6E636520736F7572636501414243C0ADF6B9B6AC17DA218FB50331EDB376701309CAAA01246E6F6E636520736F7572636501414243C09ED4ECF2DB7143A9341FDEFD125D96844E25C3C202466E6F6E636520736F7572636502414243517C16BAFADCFAB841DE3A8C617B2F20A1FB7F9EA3A3600256D68151C093C793B0116DB3D0B8BE9709304134EC9235A026844F276797");
byte[] encryptionKey = {(byte)0x02, (byte)0xEE, (byte)0xa8, (byte)0x3c, (byte)0x6c, (byte)0x12, (byte)0x11, (byte)0xe1, (byte)0x0b,
(byte) 0x9f, (byte) 0x88, (byte) 0x96, (byte) 0x6c, (byte) 0xee, (byte) 0xc3, (byte) 0x49, (byte) 0x08, (byte) 0xeb, (byte) 0x94, (byte) 0x6f, (byte) 0x7e,
(byte) 0xd6, (byte) 0xe4, (byte) 0x41, (byte) 0xaf, (byte) 0x42, (byte) 0xb3, (byte) 0xc0, (byte) 0xf3, (byte) 0x21, (byte) 0x81, (byte) 0x40};
byte[] integrityKey = {(byte) 0xbf, (byte) 0xFF, (byte) 0xec, (byte) 0x55, (byte) (byte) 0xc3, (byte) 0x01, (byte) 0x30, (byte) 0xc1, (byte) 0xd8,
(byte) 0xcd, (byte) 0x18, (byte) 0x62, (byte) 0xed, (byte) 0x2a, (byte) 0x4c, (byte) 0xd2, (byte) 0xc7, (byte) 0x6a, (byte) 0xc3, (byte) 0x3b, (byte) 0xc0,
(byte) 0xc4, (byte) 0xce, (byte) 0x8a, (byte) 0x3d, (byte) 0x3b, (byte) 0xbd, (byte) 0x3a, (byte) 0xd5, (byte) 0x68, (byte) 0x77, (byte) 0x92};
try {
byte[] plain = decrypt(ciphertext, new SecretKeySpec(encryptionKey,"HmacSHA1"),new SecretKeySpec(integrityKey,"HmacSHA1"));
} catch (DecrypterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static byte[] decrypt(byte[] ciphertext,
SecretKey encryptionKey,
SecretKey integrityKey)
throws DecrypterException {
try {
// Step 1. find the length of initialization vector and clear text.
final int plaintext_length =
ciphertext.length - INITIALIZATION_VECTOR_SIZE - SIGNATURE_SIZE;
if (plaintext_length < 0) {
throw new RuntimeException("The plain text length can't be negative.");
}
byte[] iv = Arrays.copyOf(ciphertext, INITIALIZATION_VECTOR_SIZE);
// Step 2. recover clear text
final Mac hmacer = Mac.getInstance("HmacSHA1");
final int ciphertext_end = INITIALIZATION_VECTOR_SIZE + plaintext_length;
final byte[] plaintext = new byte[plaintext_length];
boolean add_iv_counter_byte = true;
for (int ciphertext_begin = INITIALIZATION_VECTOR_SIZE, plaintext_begin = 0;
ciphertext_begin < ciphertext_end;) {
hmacer.reset();
hmacer.init(encryptionKey);
final byte[] pad = hmacer.doFinal(iv);
int i = 0;
while (i < BLOCK_SIZE && ciphertext_begin != ciphertext_end) {
plaintext[plaintext_begin++] =
(byte)(ciphertext[ciphertext_begin++] ^ pad[i++]);
}
if (!add_iv_counter_byte) {
final int index = iv.length - 1;
add_iv_counter_byte = ++iv[index] == 0;
}
if (add_iv_counter_byte) {
add_iv_counter_byte = false;
iv = Arrays.copyOf(iv, iv.length + 1);
}
}
// Step 3. Compute integrity hash. The input to the HMAC is clear_text
// followed by initialization vector, which is stored in the 1st section
// or ciphertext.
hmacer.reset();
hmacer.init(integrityKey);
hmacer.update(plaintext);
hmacer.update(Arrays.copyOf(ciphertext, INITIALIZATION_VECTOR_SIZE));
final byte[] computedSignature = Arrays.copyOf(hmacer.doFinal(), SIGNATURE_SIZE);
final byte[] signature = Arrays.copyOfRange(
ciphertext, ciphertext_end, ciphertext_end + SIGNATURE_SIZE);
if (!Arrays.equals(signature, computedSignature)) {
throw new DecrypterException("Signature mismatch.");
}
return plaintext;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("HmacSHA1 not supported.", e);
} catch (InvalidKeyException e) {
throw new RuntimeException("Key is invalid for this purpose.", e);
}
}
}

The example in the documentation appears to be broken. The test encrypted data embedded in the example archive at the end of java/Decrypter.java conveniently uses the same encryption and integrity keys, and provides us with known encrypted and plaintext data (all bytes are 0xfe).
When I patch your test main with the archive data it passes the signature test and your plaintext result is correct. When I patch Google's program with the data from the documentation page, it fails to match the signature. I believe your code is working but your test data is bad.

Related

Save image from byte array returned by Raspberry Pi UART Camera

I am currently struggling with getting a picture from a camera connected to the uart circuit of the raspberry pi. I am trying to do so with the aid of pi4j. Since I was able to initialize the camera, I do not think that the problem is related to the commands I am sending. However, when I try to open the generated .jpg the file is corrupt.
Has anyone an idea what I am doing wrong or has managed to get a picture form a camera connected to uart of the raspberry pi with java?
Camera: Grove - Serial Camera Kit
Datasheet: Grove - Serial Camera Datasheet PDF
Example Code: Python Code
private void getPicture(long pictureLength) {
try {
byte[] receiveDataPackageCommand = { (byte) 0xaa, (byte) 0x0e, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00 };
byte[] ackPackageEndCommand = { (byte) 0xaa, (byte) 0x0e, (byte) 0x00, (byte) 0x00, (byte) 0xf0,
(byte) 0xF0 };
File picture = new File(getFileName());
console.println("created file " + picture.getName());
if (picture.createNewFile()) {
FileOutputStream stream = new FileOutputStream(picture.getName());
int i = 0;
while (pictureLength > 0) {
receiveDataPackageCommand[4] = (byte) (i & 0xff);
receiveDataPackageCommand[5] = (byte) ((i >> 8) & 0xff);
serial.write(receiveDataPackageCommand);
byte[] bytes = pictureLength >= 128 ? serial.read(128) : serial.read((int) pictureLength);
stream.write(bytes);
pictureLength = pictureLength - 128;
i++;
}
stream.close();
serial.write(ackPackageEndCommand);
console.println("picture received and saved");
} else {
console.println("file already exists");
}
} catch (Exception ex) {
console.println(ex);
}
}

TripleDES encryption working fine in java but not in c#

i am facing weak key error while doing tripleDES encryption.Code working fine in java but giving error in C# .net.
i have java code in which TripleDES ecryption is working fine i need to convert my java code in c#.i am facing Weak key error during conversion.Below both java and c# code given.
1) Java Code
public class TripleDES {
private DESedeKeySpec desKeySpec;
public TripleDES(String key) {
try {
byte[] keyBytes = { (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
(byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
(byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
(byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
(byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
(byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02};
this.desKeySpec = new DESedeKeySpec(keyBytes);
} catch (Exception e) {
e.printStackTrace();
}
}
public byte[] encrypt(byte[] origData) {
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey key = factory.generateSecret(this.desKeySpec);
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(origData);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public byte[] decrypt(byte[] crypted) {
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey key = factory.generateSecret(this.desKeySpec);
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding"); //DESede/CBC/PKCS5Padding
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(crypted);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) throws Exception {
TripleDES des = new TripleDES("");
byte[] data = { (byte)0x04, (byte)0x12, (byte)0x05, (byte)0xFF, (byte)0xFB, (byte)0xA6, (byte)0x66, (byte)0xCF};
//byte[] data = { (byte)0x04, (byte)0x12, (byte)0x15, (byte)0xAF, (byte)0xFD, (byte)0xD8, (byte)0x88, (byte)0xBB};
//-----------------Edited-----------------
String text = new BigInteger(1, data).toString(16);
System.out.println("Before encryption = " +text);
byte[] crypted = des.encrypt(data);
String text1 = new BigInteger(1, crypted).toString(16);
System.out.println("Encrypted = " +text1);
byte[] decrypted = des.decrypt(crypted);
String text2 = new BigInteger(1, decrypted).toString(16);
System.out.println("Decrypted = " +text2);
}
}
2) C# Code
static void Main(string[] args)
{
String Data = EncryptDES("041205FFFBA666CF");
}
public static string EncryptDES(string InputText)
{
byte[] key = new byte[] { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 };
byte[] clearData = System.Text.Encoding.UTF8.GetBytes(InputText);
MemoryStream ms = new MemoryStream();
TripleDES alg = TripleDES.Create();
alg.Key = key;
alg.Mode = CipherMode.ECB;
CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(clearData, 0, clearData.Length);
cs.FlushFinalBlock();
byte[] CipherBytes = ms.ToArray();
ms.Close();
cs.Close();
string EncryptedData = Convert.ToBase64String(CipherBytes);
return EncryptedData;
}
Key: 02020202020202020202020202020202
Data : 041205FFFBA666CF
Result : A334C92CEC163D9F
Can anyone please write code in c# which produce result same as java.
Before I start, I want to say that I do not recommend or endorse you to follow this way for forcing TripleDES to use a key it thinks is weak, however, given that you are using it for Decryption only, here is a way to do it using Reflection.
Firstly, you must 'force' the TripeDES class to take the weak key you want to use. To do this, we use Reflection to bypass the check for a weak key that is performed when you attempt to set the key (alg.Key = key) and set the member variable directly:
//alg.Key = key; - THIS IS REPLACED BY THE BELOW
FieldInfo keyField = alg.GetType().GetField("KeyValue", BindingFlags.NonPublic | BindingFlags.Instance);
keyField.SetValue(alg, key);
The key value of TripleDES will now be set to your weak key (alg.Key);
Next you have a minor mistake, in that you have forgotten to turn off padding:
alg.Mode = CipherMode.ECB;
alg.Padding = PaddingMode.None; // Add this, as the default padding is PKCS7
Finally, there will be a further check for a weak key when creating the Decryptor, so we must use Reflection again to bypass the check and create the ICryptoTransform:
// Comment out the below line and use the code below
// CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
ICryptoTransform Decryptor;
MethodInfo createMethod = alg.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);
Decryptor = createMethod.Invoke(alg, new object[] { alg.Key, alg.Mode, alg.IV, alg.FeedbackSize, 1 }) as ICryptoTransform;
CryptoStream cs = new CryptoStream(ms, Decryptor, CryptoStreamMode.Write);
The code will now run and accept weak keys, and perform the decryption you are looking for.
However, it does not look to me that the output is what you are expecting:
?Data
"4aU3DcHkiCTEywpiewWIow=="
At least now though you are able to use whichever key you want with TripleDES.
A 3DES key is a 24-byte value which is broken down two three 8-byte values: key0, key1, key2.
Because 3DES is DES_Encrypt(key2, DES_Decrypt(key1, DES_Encrypt(key0, data))) any time key1 is equal to key2 or key0 the algorithm is reduced to DES. This is what .NET's TripleDES is warning you about.
The proper test here should account for clearing (or setting, or fixing) the parity bits in each byte, but a hand-waved version is:
SymmetricAlgorithm alg;
IEnumerable<byte> key0 = key.Take(8);
IEnumerable<byte> key1 = key.Skip(8).Take(8);
IEnumerable<byte> key2 = key.Skip(16);
if (key0.SequenceEquals(key1))
{
alg = DES.Create();
alg.Key = key2.ToArray();
}
else if (key1.SequenceEquals(key2))
{
alg = DES.Create();
alg.Key = key0.ToArray();
}
else
{
alg = TripleDES.Create();
alg.Key = key;
}
To replace your two liner:
TripleDES alg = TripleDES.Create();
alg.Key = key;

AES/GCM Encryption in VC++

I tried GCM encryption using OpenSSL library in VC++. I am getting the encrypted data, but the data is not matching with the output data as in JAVA and C#. I used same parameter credentials.
Here is the code I am using:
int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *aad,int aad_len, unsigned char *key, unsigned char *iv,unsigned char *ciphertext, unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
/* Initialise the encryption operation. */
if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
handleErrors();
/* Set IV length if default 12 bytes (96 bits) is not appropriate */
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
handleErrors();
/* Initialise key and IV */
if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
/* Provide any AAD data. This can be called zero or more times as
* required
*/
if (1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
handleErrors();
/* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
/* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
ciphertext_len += len;
/* Get the tag */
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
handleErrors();
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
The C# Code we are using
public byte[] GCM_Encryption(byte[] plainText)
{
byte[] authenticationTag;
byte[] Nonce;
byte[] AAD;
byte[] ciphertext;
string _nonce = Cur_DnT.Substring(Cur_DnT.Length - 12);
string _AAD = Cur_DnT.Substring(Cur_DnT.Length - 16);
Nonce = new byte[] { 0x2d, 0x32, 0x35, 0x54, 0x31, 0x35, 0x3a, 0x31, 0x35, 0x3a, 0x32, 0x39 };//Encoding.UTF8.GetBytes(_nonce);
AAD = new byte[] { 0x37, 0x2d, 0x30, 0x35, 0x2d, 0x32, 0x35, 0x54, 0x31, 0x35, 0x3a, 0x31, 0x35, 0x3a, 0x32, 0x39 };//Encoding.UTF8.GetBytes(_AAD);
using (AuthenticatedAesCng aes = new AuthenticatedAesCng())
{
aes.Key = new byte[] { 0xF9, 0x28, 0x01, 0x98, 0xBB, 0xC9, 0x43, 0xF8, 0x85, 0x6D, 0xA8, 0x36, 0x0F, 0x07, 0x37, 0x92, 0x7C, 0x49, 0x45, 0x29, 0x6C, 0xAF, 0xD5, 0x30, 0x1B, 0x92, 0x0E, 0x32, 0xAA, 0x20, 0xA2, 0x33 };//SKey;
aes.IV = Nonce;
aes.CngMode = CngChainingMode.Gcm;
// This data is required to verify the authentication tag, but will not go into the
// ciphertext
aes.AuthenticatedData = AAD;
// Do the encryption
using (MemoryStream ms = new MemoryStream())
using (IAuthenticatedCryptoTransform encryptor = aes.CreateAuthenticatedEncryptor())
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
// Encrypt the plaintext
byte[] plaintext = plainText;
cs.Write(plaintext, 0, plaintext.Length);
// Complete the encryption operation, and generate the authentication tag
cs.FlushFinalBlock();
// Get the generated ciphertext and authentication tag
ciphertext = ms.ToArray();
authenticationTag = encryptor.GetTag();
}
}
string ddf = BitConverter.ToString(ciphertext);
return ciphertext.Concat(authenticationTag).ToArray();
}

Get UID of Mifare Ultralight with SCL010

I want get the UID of the Mifare Ultralight NFC tag.
In Java I have this code:
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
System.out.println("Terminals: " + terminals);
CardTerminal terminal = terminals.get(0);
Card card = terminal.connect("*");
System.out.println("card: " + card);
CardChannel channel = card.getBasicChannel();
ResponseAPDU answer = channel.transmit(new CommandAPDU(0xFF, 0xCA, 0x00, 0x00, 0x00));
byte[] uid = answer.getBytes();
The problem is that I receive two bytes and not the UID.
What's the problem? Is the APDU correct?
The command you are actually using is not what you might have expected.
The correct command APDU to get the UID/serial number/enumeration identifier with this reader is:
+------+------+------+------+------+
| CLA | INS | P1 | P2 | Le |
+------+------+------+------+------+
| 0xFF | 0xCA | 0x00 | 0x00 | 0x00 |
+------+------+------+------+------+
However, the constructor you are using is defined as:
public CommandAPDU(int cla, int ins, int p1, int p2, int ne);
So with
new CommandAPDU(0xFF, 0xCA, 0x00, 0x00, 0x00)
you are creating a C-APDU with the following parameters CLA = 0xFF, INS = 0xCA, P1 = 0x00, P2 = 0x00. So far this is the same as the above APDU. But the last parameter is Ne = 0x00. Ne = 0 means that the number of expected response bytes is zero (whereas Le = 0 would mean that the number of expected response bytes is (up to) 256).
This results in effectively creating the following Case-1 APDU:
+------+------+------+------+
| CLA | INS | P1 | P2 |
+------+------+------+------+
| 0xFF | 0xCA | 0x00 | 0x00 |
+------+------+------+------+
So at most you will get the 2-byte status word as a response (either indicating success with 0x90 0x00 or indicating an error with a status code like 0x6X 0xXX).
So you can either use a byte array to form your APDU:
new CommandAPDU(new byte[] { (byte)0xFF, (byte)0xCA, (byte)0x00, (byte)0x00, (byte)0x00 } )
Or you can specify a proper value for Ne:
new CommandAPDU(0xFF, 0xCA, 0x00, 0x00, 256)
import java.nio.ByteBuffer;
import java.util.List;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.TerminalFactory;
public class Read {
public Read() {
try {
CardTerminal terminal = null;
// show the list of available terminals
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
String readerName = "";
for (int i = 0; i < terminals.size(); i++) {
readerName = terminals.get(i).toString()
.substring(terminals.get(i).toString().length() - 2);
//terminal = terminals.get(i);
if (readerName.equalsIgnoreCase(" 0")) {
terminal = terminals.get(i);
}
}
// Establish a connection with the card
System.out.println("Waiting for a card..");
if(terminal==null)
return;
terminal.waitForCardPresent(0);
Card card = terminal.connect("T=0");
CardChannel channel = card.getBasicChannel();
// Start with something simple, read UID, kinda like Hello World!
byte[] baReadUID = new byte[5];
baReadUID = new byte[] { (byte) 0xFF, (byte) 0xCA, (byte) 0x00,
(byte) 0x00, (byte) 0x00 };
System.out.println("UID: " + send(baReadUID, channel));
// If successfull, the output will end with 9000
// OK, now, the real work
} catch (Exception ex) {
ex.printStackTrace();
}
}
public String send(byte[] cmd, CardChannel channel) {
String res = "";
byte[] baResp = new byte[258];
ByteBuffer bufCmd = ByteBuffer.wrap(cmd);
ByteBuffer bufResp = ByteBuffer.wrap(baResp);
// output = The length of the received response APDU
int output = 0;
try {
output = channel.transmit(bufCmd, bufResp);
}` catch (CardException ex) {
ex.printStackTrace();
}`
for (int i = 0; i < output; i++) {
res += String.format("%02X", baResp[i]);
// The result is formatted as a hexadecimal integer
}
return res;
}
public static void main(String[] args) {
new Read();
}
}
After read this code For read and write purpose use bellow commands.
And Read From page : 04 to page : 07 Command is:
read_four_to_seven = new byte[]{(byte) 0xFF, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x05, (byte) 0x0D4, (byte) 0x40, (byte) 0x01,
(byte) 0x30, (byte) 0x04, (byte) 0x07 };
System.out.println("Read : " + send(read_four_to_seven, channel));
Write into Page 04:
Write_Page_Four = new byte[] { (byte) 0xFF, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x15, (byte) 0xD4, (byte) 0x40,
(byte) 0x01, (byte) 0xA0, (byte) 0x04, (byte) 0x4D,
(byte) 0x65, (byte) 0x73, (byte) 0x75, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00 };
System.out.println("Read : " + send(Write_Page_Four, channel));

password based en/decrypting in java: fails to decrypt the file even though the password is identical

I wrote the following code for text file encryption and decryption.
The encryption process works fine but I cannot decrypt the created file. For some reason, even though I use the same password, with the same length and same paddings, the decryption output is an encoded file different from the original one...
In other attempts I failed while running encryption and decryption in separated runs. But now they are both running one after another (even though they are using different key-spec, is that the reason? if so - how can I bypass it?)
public static void main(String[] args) throws Exception {
encrypt("samplePassword", new FileInputStream("file.txt"), new FileOutputStream("enc-file.txt"));
decrypt("samplePassword", new FileInputStream("enc-file.txt"), new FileOutputStream("file-from-enc.txt"));
}
public static void encrypt(String password, InputStream is, OutputStream os) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(password(password), "TripleDES");
Cipher cipher = Cipher.getInstance("TripleDES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] buf = new byte[8096];
os = new CipherOutputStream(os, cipher);
int numRead = 0;
while ((numRead = is.read(buf)) >= 0) {
os.write(buf, 0, numRead);
}
os.close();
}
public static void decrypt(String password, InputStream is, OutputStream os) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(password(password), "TripleDES");
Cipher cipher = Cipher.getInstance("TripleDES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] buf = new byte[8096];
CipherInputStream cis = new CipherInputStream(is, cipher);
int numRead = 0;
while ((numRead = cis.read(buf)) >= 0) {
os.write(buf, 0, numRead);
}
cis.close();
is.close();
os.close();
}
private static byte[] password(String password) {
byte[] baseBytes = { (byte) 0x38, (byte) 0x5C, (byte) 0x8, (byte) 0x4C, (byte) 0x75, (byte) 0x77, (byte) 0x5B, (byte) 0x43,
(byte) 0x1C, (byte) 0x1B, (byte) 0x38, (byte) 0x6A, (byte) 0x5, (byte) 0x0E, (byte) 0x47, (byte) 0x3F, (byte) 0x31,
(byte) 0xF, (byte) 0xC, (byte) 0x76, (byte) 0x53, (byte) 0x67, (byte) 0x32, (byte) 0x42 };
byte[] bytes = password.getBytes();
int i = bytes.length;
bytes = Arrays.copyOf(bytes, 24);
if(i < 24){
for(;i<24; i++){
bytes[i] = baseBytes[i];
}
}
return bytes;
}
can any one give me a hint?
On a first look,
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
should probably be
cipher.init(Cipher.DECRYPT_MODE, keySpec);
in the decrypt method.
Have a look at the documentation.

Categories