<commit_before>#load "utils.fs"

open Utils
open System
open System.Text

let strings =
    [|"<KEY>;
      "<KEY>;
      "<KEY>;
      "<KEY>;
      "<KEY>";
      "<KEY>;
      "<KEY>;
      "<KEY>;
      "<KEY>;
      "<KEY>"|]

let key = Utils.randKey 16 |> Utils.bytesToStr
let iv = Utils.IV

let testEncrypt =
    let rnd = Random()
    strings.[rnd.Next 9] |> Convert.FromBase64String |> Utils.CBCEncrypt key iv

let paddingOracle (code: byte []) : bool = 
    code |> Utils.CBCDecryptKeepPad key iv |> Utils.validPKCS7
    
let testDecrypt = testEncrypt |> paddingOracle

(* padding oracle attack *)

let genGuesses (code: byte []) s offset (found: byte []): (byte * byte []) list =
    let guessByte n =
        Utils.xorArrs [ [|code.[s+offset]|]; [|byte n|]; [|byte (16-offset)|] ]
    let padding n = Utils.repeat (byte n) |> Seq.take (n-1) |> Seq.toArray
    let foundBytes =
        let f = Utils.xorArrs [ code.[s+offset+1..s+15]; padding (16-offset); found ]
        printfn "%A" f
        f
    let genGuess i: byte [] =
        Array.concat [| code.[s..(s+offset-1)];
                        guessByte i; foundBytes;
                        code.[(s+16)..(s+31)] |]
    [ for i in [0..255] do yield (byte i, genGuess i) ]

let rec evalGuesses ind (guesses: (byte * byte []) list) : (byte * byte []) =
    match guesses with
        | (b,x)::[] -> (b, x)
        | (b,x)::xs -> if paddingOracle x = true then (b, x)
                       else evalGuesses ind xs 
        | _         -> (0uy, [||])

let genBlock (bs: byte []) n =
    Utils.xorArr [|for _ in [0..n] do yield byte n |] bs.[(16-n)..]
    |> Array.ofSeq

let disambiguate (b: byte, bs: byte []) : byte [] =
    let rec check pairs =
        match pairs with
            | []        -> [|b|]
            | (n,x)::_ -> if paddingOracle x = false then check (List.tail pairs)
                          else genBlock x n        
    [ for i in [1..15] do
          yield (i+1, Array.concat [| bs.[0..(15-i-1)];
                                      Utils.xorArr [|bs.[(15-i)]|] [|1uy|] 
                                      bs.[(15-i+1)..15] |]) ]
    |> check

let decryptLastByte code start : byte [] =
    genGuesses code start 15 [||]
    |> evalGuesses 15
    |> disambiguate     

let decryptByte code start offset found : byte [] =
    genGuesses code start offset found
    |> evalGuesses offset
    |> fst
    |> Array.create 1

let rec decryptBlock start offset (found: byte []) (code: byte []): byte [] =
    match offset with
        | -1 -> found
        | 15 -> let bs = decryptLastByte code start
                decryptBlock start (offset-(Array.length bs)) bs code
        | _  -> let b = decryptByte code start offset found
                decryptBlock start (offset-1) (Array.append b found) code

let CBCPaddingDecrypt (code: byte []) =
    let numBlocks = Array.chunkBySize 16 code |> Array.length |> (+) -1
    [| for i in [0..numBlocks] do
           yield Array.append iv code |> decryptBlock (i*16) 15 [||] |]
    |> Array.concat

let text = CBCPaddingDecrypt testEncrypt |> Utils.bytesToStr<commit_msg>refactoring where padding is added<commit_after>#load "utils.fs"

open Utils
open System
open System.Text

let strings =
    [|"<KEY>;
      "<KEY>;
      "<KEY>;
      "<KEY>;
      "<KEY>";
      "<KEY>;
      "<KEY>;
      "<KEY>;
      "<KEY>;
      "<KEY>"|]

let key = Utils.randKey 16 |> Utils.bytesToStr
let iv = Utils.IV

let testEncrypt =
    let rnd = Random()
    strings.[rnd.Next 9] |> Convert.FromBase64String |> Utils.CBCEncrypt key iv

let paddingOracle (code: byte []) : bool = 
    code |> Utils.CBCDecryptKeepPad key iv |> Utils.validPKCS7
    
let testDecrypt = testEncrypt |> paddingOracle

(* padding oracle attack *)

let genGuesses (code: byte []) s offset (found: byte []): (byte * byte []) list =
    let guessByte n =
        Utils.xorArr [|code.[s+offset]|] [|byte n|] 
    let padding n = Utils.repeat (byte n) |> Seq.take (n-1) |> Seq.toArray
    let foundBytes =
        let f = Utils.xorArrs [ code.[s+offset+1..s+15]; padding (16-offset); found ]
        printfn "%s" (found |> Utils.bytesToStr)
        f
    let genGuess i: byte [] =
        Array.concat [| code.[s..(s+offset-1)];
                        guessByte i; foundBytes;
                        code.[(s+16)..(s+31)] |]
    [ for i in [0..255] do yield (byte i, genGuess i) ]

let rec evalGuesses ind (guesses: (byte * byte []) list) : (byte * byte []) =
    match guesses with
        | (b,x)::[] -> (b, x)
        | (b,x)::xs -> if paddingOracle x = true then (b, x)
                       else evalGuesses ind xs 
        | _         -> (0uy, [||])

let genBlock (bs: byte []) n =
    Utils.xorArr [|for _ in [0..n] do yield byte n |] bs.[(16-n)..]
    |> Array.ofSeq

let disambiguate (b: byte, bs: byte []) : byte [] =
    let rec check pairs =
        match pairs with
            | []       -> Utils.xorArr [|b|] [|1uy|]
            | (n,x)::_ -> if paddingOracle x = false then check (List.tail pairs)
                          else genBlock x n
    [ for i in [1..15] do
          yield (i+1, Array.concat [| bs.[0..(15-i-1)];
                                      Utils.xorArr [|bs.[(15-i)]|] [|1uy|] 
                                      bs.[(15-i+1)..15] |]) ]
    |> check

let decryptLastByte code start : byte [] =
    genGuesses code start 15 [||]
    |> evalGuesses 15
    |> disambiguate     

let decryptByte code start offset found : byte [] =
    genGuesses code start offset found
    |> evalGuesses offset
    |> fst
    |> Array.create 1
    |> Utils.xorArr [|byte (16 - offset)|]

let rec decryptBlock start offset (found: byte []) (code: byte []): byte [] =
    match offset with
        | -1 -> found
        | 15 -> let bs = decryptLastByte code start
                decryptBlock start (offset-(Array.length bs)) bs code
        | _  -> let b = decryptByte code start offset found
                decryptBlock start (offset-1) (Array.append b found) code

let CBCPaddingDecrypt (code: byte []) =
    let numBlocks = Array.chunkBySize 16 code |> Array.length |> (+) -1
    [| for i in [0..numBlocks] do
           yield Array.append iv code |> decryptBlock (i*16) 15 [||] |]
    |> Array.concat

let text = CBCPaddingDecrypt testEncrypt |> Utils.bytesToStr
{'fraction_non_alphanumeric': 0.15253698107205343, 'fraction_numerical': 0.01924606330523302, 'mean_word_length': 1.98292220113852, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2700825', 'n_tokens_mistral': 2262, 'n_tokens_neox': 2121, 'n_words': 614}