working on a problem of encrypyting and decrypting using the DES given in java.
Ive already figured out how to encrypt and decrypt pretty easy but now im stuck.
For the current problem i am having I have the plaintext and the coorisponding cipher text (which is in the format of 8 hex pairs ex: A5 33 1F ..) but i also have the first 4 hexidecimal bits of the key. Im not really asking for code but more of an idea how i would go about tackling this problem! anything will help! this is my decryption code (just included it to show i am workin hard :) ). thanks guys!
public static void decrypt(){
Cipher cipher;
SecretKeySpec key;
byte [] keyBytes;
byte [] pt;
byte [] ct;
String plaintxt;
keyBytes = new byte [] {(byte)0xFE, (byte)0xDC, (byte)0xBA, (byte)0x98, (byte)0x76, (byte)0x54, (byte)0x32, (byte)0x10};
key = new SecretKeySpec(keyBytes, "DES");
ct = new byte [] {(byte) 0x2C, (byte) 0xE6, (byte) 0xDD, (byte) 0xA4, (byte) 0x98, (byte) 0xCA, (byte) 0xBA, (byte) 0xB9};
try{
cipher = Cipher.getInstance("DES/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, key);
pt = cipher.doFinal(ct);
printByteArray(pt);
plaintxt = byteToHex(pt);
hexToAscii(plaintxt);
}
catch(Exception e){
e.printStackTrace();
}
}
Brute force.
Enumerate over every key that it could be (given the fixed bytes) until you get a decryption that makes the plaintext and ciphertext match. It'll take edit: 2^37 attempts on average, though, so don't expect it to happen fast :)
There are some properties of DES that let you crack it faster, but they're very difficult to implement and I doubt you'd be expected to learn them. But if you are interested, http://en.wikipedia.org/wiki/Data_Encryption_Standard#Security_and_cryptanalysis
Related
Assume two clients are exchanging secure messages back and forth.
Must this block be run every time for each message, or can any step(s) be done just once at start:
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
output = cipher.doFinal(content);
I guess to lend some context- although I don't (yet) understand the internals completely, it is my understanding that for security purposes it's important to change the IV for each message. So I think the answer to this question will depend on whether that step happens under the hood at the doFinal() stage or init()....?
You are correct: to be safe you need to use a new,random, IV for each message. This means you either need to recreate the cipher or randomly set the IV yourself for each subsequent message. The former is probably safer since if you change ciphers or modes, there maybe some other state you need to randomly set as well and reinitializing the cipher should handle all of it.
If you don't do this, you end up with the same rather bad bug SSL had with IV reuse.
Cipher.doFinal does not reset the cipher to a random IV. In fact, its far worse than that, it appears to reset the internal state to the same IV you started with. As shown by this code.
Cipher f = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
f.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = f.getIV();
System.out.println(Arrays.toString(f.doFinal("hello".getBytes())));
System.out.println(Arrays.toString(f.getIV()));
System.out.println(Arrays.toString(f.doFinal("hello".getBytes())));
System.out.println(Arrays.toString(f.getIV()));
System.out.println( Arrays.equals(f.getIV(), iv)); // true
I'm getting an error everytime I run this
"Error: Given final block not properly padded"
Basically I'm trying to brute force the last 3 bytes of the key, the first 13 bytes are correct.
Any idea what am I doing wrong? I tried removing the padding and it works but it couldn't find the plaintext that I'm sure it exists and contains the word "Mary had".
Note: I'm using sun.misc.BASE64Decoder
here's a part of my code.
String myiv = new String(new byte[] {
0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x31,0x30,0x31,0x31,0x31,0x32,0x33
});
char [] mykeyarray = new char[] {0x86,0xe5,0x30,0x90,0xff,0x62,0xa0,0x9a,0x81,0x00,0xad,0x9e,0x8f,0x00,0x00,0x00};
String encoded = "dm8cfvs+c7pKM+WR+fde8b06SB+lqWLS4sZW+PfQSKtTfgPknzYzpTVOtJP3JBoU2Uo/7XWopjoPDOlPr24duuck0z+vAx91bYTwQo4INnIIBkj/lhJMWmvAKaUIO3qzBoGg8ynQOhuG6LY7Wo0uww==";
IvParameterSpec ivspec = new IvParameterSpec(myiv.getBytes());
byte [] decoded;
FileWriter fstream = new FileWriter("out.txt");
BufferedWriter out = new BufferedWriter(fstream);
String mykey;
int repeat = 256;
outerloop:
for(int i=0;i<repeat;i++){
for(int j=0;j<repeat;j++){
for(int k=0;k<repeat;k++){
mykey = new String(mykeyarray);
SecretKeySpec keyspec = new SecretKeySpec(mykey.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
System.out.println("I: "+i+" J: "+j+" K: "+k);
decoded = new BASE64Decoder().decodeBuffer(encoded);
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
byte [] decrypted = cipher.doFinal(decoded);
String dec = new String(decrypted);
if(dec.contains("Mary")){
out.write(dec);
out.write("\n");
System.out.println(dec);
break outerloop;
}
mykeyarray[15]++;
}
mykeyarray[14]++;
mykeyarray[15]=0x00;
}
mykeyarray[13]++;
mykeyarray[14]=0x00;
mykeyarray[15]=0x00;
}
out.close();
}
catch(Exception e){
System.out.println("Error: " + e.getMessage());
}
}
}
Your code makes many many mistakes, and I don't know what you are trying to accomplish. So I'll explain why you may receive a BadPaddingException for a CBC cipher:
your key is incorrect
one or both of the last two blocks of ciphertext have been altered
one or more blocks have been removed from the end of the ciphertext
the IV is incorrect and the ciphertext consists of a single block
Good luck hunting down the cause of the exception.
Try to learn more about PKCS#5 padding. It's a special bytes beeing added to plain text before encryption. It can't be correct if the text was decrypted with a wrong key. If you brute-force a key, you will take this error on each key except correct one.
Since decrypting with a random key gives you a random message, you usually don't get correct padding. Just catch the exception and move on.
You will get padding errors approximately 93% of the time when brute forcing a PKCS5 padded message. PKCS5 padding pads out your message with bytes containing the length of the padding. So valid padding is 0x01, 0x2 0x02, 0x03 0x03 0x03, ...., 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF. The odds of correct padding happening in a random message are 1/16 + (1/16)^2 ... (1/16)^16 <.067. Which means you get incorrect padding about 1- %6.7 = 93% of the time.
I want to encrypt a frame using DES using a given key.
The padding style I am using is PKCS5Padding. This pads the string with 02 02 if 2 bytes are to be added and with 03 03 03 if 3 bytes are to be added to make multiple of 8.
But my requirement is to pad a string with my particular bytes. e.g if 2 bytes are to be added then 30 30 and 3 bytes are to be added then 30 30 30 (in hex 0's value is 30). Also, I must know how many padded bytes have been added.
Which padding technique should I follow and how can I use it?
Below is my code for encryption:
byte[] keyValue = new byte[]{(byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x16,(byte) 0x05, (byte) 0x12};
myKeySpec = new DESKeySpec(keyValue);
mySecretKeyFactory = SecretKeyFactory.getInstance("DES");
key = mySecretKeyFactory.generateSecret(myKeySpec);
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
IvParameterSpec iv2 = new IvParameterSpec(new byte[8]);
cipher.init(Cipher.ENCRYPT_MODE, key, iv2);
byte[] plainText = function.HexStringToByteArray(payloadRecv);
byte[] encryptedText = cipher.doFinal(plainText);
Do not select PKCS5Padding in the cipher specification. Select NoPadding. You'll have to add the padding onto the data yourself prior to encrypting it. After decrypting it (also using no padding), you'll have to inspect the last byte to know how many bytes of padding to remove and remove it yourself.
Basically, just code exactly what you described.
Someone asked me to decrypt with PHP a string encrypted with the following Java Class.
public class CryptoLibrary {
private Cipher encryptCipher;
private sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
public CryptoLibrary() throws SecurityException{
java.security.Security.addProvider(new com.sun.crypto.provider.SunJCE());
char[] pass = "NNSHHETJKKSNKH".toCharArray();
byte[] salt = {
(byte) 0xa3, (byte) 0x21, (byte) 0x24, (byte) 0x2c,
(byte) 0xf2, (byte) 0xd2, (byte) 0x3e, (byte) 0x19 };
init(pass, salt, iterations);
}
public void init(char[] pass, byte[] salt, int iterations)throws SecurityException{
PBEParameterSpec ps = new javax.crypto.spec.PBEParameterSpec(salt, 20);
SecretKeyFactory kf = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey k = kf.generateSecret(new javax.crypto.spec.PBEKeySpec(pass));
encryptCipher = Cipher.getInstance("PBEWithMD5AndDES/CBC/PKCS5Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, k, ps);
}
}
public synchronized String encrypt(String str) throws SecurityException{
if(str!=null){
byte[] utf8 = str.getBytes("UTF8");
byte[] enc = encryptCipher.doFinal(utf8);
return encoder.encode(enc);
}
else {
return null;
}
}
}
I don't know any Java so I need some help to understand this encryption.
1) what is the meaning of this line?
PBEParameterSpec ps = new javax.crypto.spec.PBEParameterSpec(salt,20);
2) what value should I use for the first parameter of
string mcrypt_encrypt ( string $cipher , string $key , string $data , string $mode [, string $iv ] )
3) When should I use MD5 in my php script?
I had to do the same thing for a customer of mine and wrote a few lines of code to help with issue: https://github.com/kevinsandow/PBEWithMD5AndDES
1) It creates the parameters for Password Based Encryption, the salt, which is included in the hash calculations, and the number of iterations that the hash method is executed (on it's own output). It is used to defeat rainbow table attacks, basically an attacker has to go through the same number of iterations to check if the password is correct, and he cannot use a precalculated table because the salt will be different for each password (so you cannot see if somebody has the same password as another user).
2) MCRYPT_DES, and you will need MCRYPT_MODE_CBC for the mode, and PKCS#5 padding of course.
3) Only when you are absolutely sure that its weaknesses are not exposed or when absolutely required for compatibility. Fortunately, it is relatively secure for key derivation functions. Download a pbkdf1 method for PHP and put it in there - if not already included.
The following code in java attempts to decrypt a string encoded in a QR code, encrypted in C# code. it seems to fail to decrypt the string. is there an easy way of doing this???
//string encrypted contains the string of the encoded characters.
String encrypted = intent.getStringExtra("SCAN_RESULT");
//converting the string into a byte array
byte[] byteEncrypted = encrypted.getBytes();
//instantiating the AES cipher object
Cipher cipher = Cipher.getInstance("AES");
//Predefined public-key
byte[] skey = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
//creating a secretKeySpec
SecretKeySpec skeyspec = new SecretKeySpec(skey, "AES");
//initializing the cipher to Decrypt
cipher.init(Cipher.DECRYPT_MODE, skeyspec);
final byte[] decrypt = cipher.doFinal(byteEncrypted);
//decrypting the string
String contents = new String(decrypt, "UTF-8");
For starters, you generally can't convert a cipher text stored as text, and convert it directly to bytes with a call to getBytes().
AES cipher text contains bytes with values from 0 to 255; I know of no character set encoding that maps all 256 values to a character, and even if there is one, it's unlikely to be your platform default encoding, and you aren't specifying it in your text-to-byte conversion.
The most common byte-to-text transformation for cipher text is Base-64 encoding. If that's what you are using here, you'll have to find or write a base-64 decoding utility.
You should also specify a complete transformation when creating the Cipher instance; otherwise, a provider specific default is used, and that might not match the sender's choices.
Since you don't show any IV, you might be using ECB as the mode. For most messages, this is insecure. It can only be safe if your message is a large random number (like a session identifier).
Most likely the padding is PKCS #5 padding (called PKCS7Padding in .NET), but you might have no padding, or some home-brew padding algorithm.
Assuming ECB and PKCS #5 padding, your cipher creation should look like this:
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");