(load (expand-file-name "../util" (file-name-directory (or load-file-name buffer-file-name)))) (require 'seq) (setq plaintext (base64-to-bytes "Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBqdXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUgYnkK")) (setq key (random-bytes aes-128-key-size)) (defun encryption-oracle (input) (aes-128-ecb-encrypt (pkcs7pad (concat input plaintext)) key)) (defun detect-blocksize () (let ((input "") (last-length (length (encryption-oracle "")))) (catch 'exit (while t (setq input (concat input "A")) (let ((new-length (length (encryption-oracle input)))) (when (> new-length last-length) (throw 'exit (- new-length last-length))) (setq last-length new-length)))))) (defun detect-ecb (blocksize) (let ((plaintext (make-string (* blocksize 3) ?A))) (repeated-block-p (seq-partition (encryption-oracle plaintext) blocksize)))) ;; |AAAAAAAAAAAAAAA?|????????????????|??????PPPPPPPPPP| 15+0=15 ;; |AAAAAAAAAAAAAAs?|????????????????|?????PPPPPPPPPPP| 14+1=15 ;; |AAAAAAAAAAAAAse?|????????????????|????PPPPPPPPPPPP| 13+2=15 ;; ... ;; |AAAAAAAAAAAAAAAA|secret123secret?|???????PPPPPPPPP| 16+15=31 ;; |AAAAAAAAAAAAAAAs|ecret123secret4?|??????PPPPPPPPPP| 15+16=31 ;; |AAAAAAAAAAAAAAse|cret123secret45?|?????PPPPPPPPPPP| 14+17=31 ;; ... ;; |AAAAAAAAAsecret1|23secret456secr?|PPPPPPPPPPPPPPPP| 9+22=31 ;; |AAAAAAAAsecret12|3secret456secreP| 8+23=31 (defun guess-byte (known blocksize) (let* ((short-block-count (1+ (/ (1+ (length known)) blocksize))) (padsize (- (* short-block-count blocksize) (length known) 1)) (input (make-string padsize ?A)) (block-idx (/ (+ padsize (length known)) blocksize)) (block (elt (seq-partition (encryption-oracle input) blocksize) block-idx))) (catch 'return (dotimes (i 128) (let* ((input (concat (make-string padsize ?A) known (string i))) (match (elt (seq-partition (encryption-oracle input) blocksize) block-idx))) (when (equal block match) (throw 'return i)))) (throw 'return nil)))) (setq blocksize (detect-blocksize)) (message "Detected blocksize: %d" blocksize) (when (detect-ecb blocksize) (message "Detected ECB")) (let ((known "") guessed-bytes guessed-byte) (while (setq guessed-byte (guess-byte known blocksize)) (princ (format "%c" guessed-byte)) (send-string-to-terminal "") ; flush stdout (setq known (concat known (string guessed-byte)))))