Noor
Noor

Reputation: 1

AES 128 how to brute force with partial key in python

I am beginner in python so I need help I have encrypted file and partial key file ,the partial key file have 96 bit out of 128 so i need to guess the rest of the key and decrypt the file ,the hint is the first word is "hello" in the encrypted my questions: how to guess the rest of key ? how to check if the key is the right key and how much time did take?

Upvotes: 0

Views: 4432

Answers (1)

Michael Fehr
Michael Fehr

Reputation: 6414

Sorry that the source code in my answer is in Java but up to now I never wrote a single line in python. As you showed us nearly no self written code I assume you need a path to find a way to do it in python.

Some basics to start with - AES 128 encryption has a 128 bit or 16 bytes long key for encryption and later decryption. You told us that you already know 96 bits = 12 bytes so there are "just" 4 bytes left to guess. Each byte has a "capacity" of (integer) 256 so in maximum you would have to test 256 * 256 * 256 * 256 combinations = 4,294,967,296 combinations. Assuming that the key is of random you need half of this to try to find the real key so in real there are 2,147,483,648 combinations - a todays home computer does this within an hour or less.

Below you find my code and I setup an online compiler with the code - in this code I "restricted" the search for the last 2 bytes (so it assumes that 14 of the 16 bytes are known) because the online compiler would abort the program with a "running too long" runtime error.

The code is well commented and not optimized for speed but for readability. In the end you get an output like this one (as I'm using a random key and initialization vector for AES in CBC mode your output will be different), the online compiler is available here: https://repl.it/@javacrypto/JavaAesCbc128BruteForce:

AES CBC String Encryption - brute force decryption
key      length: 16 data: 0cb878f9da009be3ef487f54aa8c3230
keyGuess length: 16 data: 0cb878f9da009be3ef487f54aa8c0000
*** key found ***
key      length: 16 data: 0cb878f9da009be3ef487f54aa8c3230
plaintext: hello this is just plaintext

code:

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println("AES CBC String Encryption - brute force decryption");

        String plaintext = "hello this is just plaintext";
        // this plaintext beginning is known
        String plaintextKnown = "hello";
        byte[] plaintextKnownByte = plaintextKnown.getBytes(StandardCharsets.UTF_8);
        // number of known bytes of the key
        int numberKeyBytes = 14; // 14 bytes = 112 bit known bits
        // random key & iv
        SecureRandom random = new SecureRandom();
        byte[] key = new byte[16]; // 16 byte = 128 bit keylength
        random.nextBytes(key);
        byte[] iv = new byte[16];
        random.nextBytes(iv);
        System.out.println("key      length: " + key.length + " data: " + bytesToHex(key));
        // setup cbc
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec);
        // get plaintext
        byte[] plaintextByte = plaintext.getBytes(StandardCharsets.UTF_8);
        byte[] ciphertextByte = cipher.doFinal(plaintextByte);

        byte[] keyGuessed = new byte[16];
        System.arraycopy(key, 0, keyGuessed, 0, numberKeyBytes ); // copy first 14 bytes = 112 bit
        System.out.println("keyGuess length: " + keyGuessed.length + " data: " + bytesToHex(keyGuessed));
        for (int a = 0; a < 256; a++) {
            for (int b = 0; b < 256; b++) {
                for (int c = 0; c < 256; c++) {
                    for (int d = 0; d < 256; d++) {
                        keyGuessed[15] = (byte) d;
                        //System.out.println("keyGuess length: " + keyGuessed.length + " data: " + bytesToHex(keyGuessed));
                        decryptAesCbc128(keyGuessed, iv, ciphertextByte, plaintextKnownByte);
                    }
                    keyGuessed[14] = (byte) c;
                }
                keyGuessed[13] = (byte) b;
            }
            keyGuessed[12] = (byte) a;
        }
    }

    private static boolean decryptAesCbc128(byte[] key, byte[] iv, byte[] ciphertext, byte[] plaintextbyteKnown) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException {
        SecretKeySpec keySpecDecode = new SecretKeySpec(key, "AES");
        IvParameterSpec ivParameterSpecDecode = new IvParameterSpec(iv);
        Cipher cipherDecrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipherDecrypt.init(Cipher.DECRYPT_MODE, keySpecDecode, ivParameterSpecDecode);
        byte[] decryptedtext = new byte[0];
        try {
            decryptedtext = cipherDecrypt.doFinal(ciphertext);
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            //e.printStackTrace();
            return false;
        }
        // partial array comparison
        boolean found = ByteBuffer.wrap(decryptedtext, 0, 5).equals(ByteBuffer.wrap(plaintextbyteKnown, 0, 5));
        if (found == false) {return false;}
        System.out.println("*** key found ***");
        System.out.println("key      length: " + key.length + " data: " + bytesToHex(key));
        System.out.println("plaintext: " + new String(decryptedtext));
        System.exit(0);
        return true;
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuffer result = new StringBuffer();
        for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
        return result.toString();
    }
}

Upvotes: 1

Related Questions