Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // provide aiw4421.bin on stdin, get unpacked binary config on stdout.
- import java.security.MessageDigest;
- import javax.crypto.Cipher;
- import javax.crypto.spec.*;
- import java.io.*;
- import java.util.*;
- class XtractCfg {
- static class BytePairDecompressionStream extends FilterOutputStream {
- boolean escaped = false;
- int escapechar;
- ByteArrayOutputStream mapstream = new ByteArrayOutputStream();
- int mapstreamsize = -2;
- java.util.Map<Integer,Short> pairexpansion;
- public BytePairDecompressionStream(OutputStream parent) {
- super(parent);
- }
- public void write(int b) throws IOException {
- if (pairexpansion != null) {
- if (escaped)
- {
- super.write(b);
- escaped = false;
- } else if((b & 0xff) == escapechar) {
- escaped = true;
- } else {
- Short expansion = pairexpansion.get(b & 0xFF);
- if (expansion == null)
- super.write(b);
- else {
- super.write(expansion.shortValue() >> 8);
- super.write(expansion.shortValue() & 0xFF);
- }
- }
- }
- else if (mapstreamsize == -2) {
- escapechar = b & 0xff;
- mapstreamsize = -1;
- } else if (mapstreamsize == -1) {
- mapstreamsize = 3*b;
- } else if (mapstream.size() < mapstreamsize) {
- mapstream.write(b);
- } else {
- if (b != 0x5b)
- throw new IOException("Bad magic after map");
- pairexpansion = new TreeMap<Integer,Short>();
- byte[] mapdata = mapstream.toByteArray();
- mapstream = null;
- for(int i = 0;i < mapdata.length / 3;i++)
- pairexpansion.put(new Integer(mapdata[i*3] & 0xFF),new Short((short)((mapdata[i*3+1] & 0xFF) * 0x100 +
- (mapdata[i*3+2] & 0xFF))));
- }
- }
- }
- static final byte[] key0 = {(byte)0x1d,(byte)0xe5,(byte)0xfa,(byte)0xb8,(byte)0x81,(byte)0x91,(byte)0x00,(byte)0x84,
- (byte)0x11,(byte)0xaf,(byte)0x53,(byte)0xdd,(byte)0xe4,(byte)0x89,(byte)0xea,(byte)0xfd};
- static final byte[] key1 = {(byte)0xa9,(byte)0xdc,(byte)0x0e,(byte)0xf0,(byte)0x28,(byte)0x67,(byte)0x91,(byte)0xac,
- (byte)0xc9,(byte)0x13,(byte)0x86,(byte)0x5d,(byte)0x2d,(byte)0xf8,(byte)0x20,(byte)0x99};
- static final byte[] key2 = {(byte)0x1a,(byte)0xa8,(byte)0x80,(byte)0xb5,(byte)0x44,(byte)0x11,(byte)0xf1,(byte)0x19,
- (byte)0x0c,(byte)0xca,(byte)0x3d,(byte)0xe8,(byte)0x77,(byte)0x41,(byte)0x37,(byte)0x89};
- static final byte[] key3 = {(byte)0x45,(byte)0x68,(byte)0x70,(byte)0x98,(byte)0x7a,(byte)0xcd,(byte)0xeb,(byte)0xbb,
- (byte)0xbd,(byte)0xed,(byte)0xa8,(byte)0x03,(byte)0x98,(byte)0x73,(byte)0x40,(byte)0x24};
- static final byte[][] keys = {key0, key1, key2, key3};
- static void doit(InputStream source, OutputStream sink) throws Exception {
- Cipher c = Cipher.getInstance("AES/CTS/NoPadding");
- byte[] iv = new byte[16];
- source.read(iv);
- c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key0, "AES"), new IvParameterSpec(iv));
- byte[] header = new byte[0x28];
- source.read(header);
- DataInput hdrstream = new DataInputStream(new ByteArrayInputStream(c.doFinal(header)));
- if(hdrstream.readInt() != 0x59585756)
- throw new Exception("Bad magic");
- int size = hdrstream.readInt();
- int keynum = hdrstream.readByte();
- if(keynum > 3 || keynum < 0)
- throw new Exception("Bad key number (0-3 expected)");
- byte[] expectedmd5 = new byte[16];
- hdrstream.readFully(expectedmd5);
- byte[] body = new byte[size];
- source.read(body);
- byte[] actualmd5 = MessageDigest.getInstance("MD5").digest(body);
- if(!MessageDigest.isEqual(actualmd5, expectedmd5))
- throw new Exception("Body MD5 does not match");
- c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keys[keynum], "AES"), new IvParameterSpec(body, 0, 16));
- byte[] payload = c.doFinal(body,16, size-16);
- DataInput bodystream = new DataInputStream(new ByteArrayInputStream(payload));
- if(bodystream.readInt() != 0x48464442)
- throw new Exception("Bad body magic");
- int payloadsize = bodystream.readInt();
- bodystream.skipBytes(1); /* key ID - unused as no further crypto layer is present */
- bodystream.readFully(expectedmd5);
- MessageDigest md5 = MessageDigest.getInstance("MD5");
- md5.update(payload, 0x28, payloadsize);
- actualmd5 = md5.digest();
- if(!MessageDigest.isEqual(actualmd5, expectedmd5))
- throw new Exception("Payload MD5 does not match");
- DataInputStream payloadhdrstream = new DataInputStream(new ByteArrayInputStream(payload, 0x28, 6));
- if(payloadhdrstream.readUnsignedShort() != 0x6562)
- throw new Exception("Byte-pair compression magic does not match");
- int levels = payloadhdrstream.readUnsignedByte();
- int compressedsize = payloadhdrstream.readUnsignedByte() * 0x10000;
- compressedsize += payloadhdrstream.readUnsignedShort();
- OutputStream str = sink;
- for(int i = 0; i < levels; i++)
- str = new BytePairDecompressionStream(str);
- str.write(payload, 0x28+6, compressedsize);
- str.flush();
- }
- public static void main(String[] args) throws Exception{
- doit(System.in, System.out);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement