CTR mode is not idempotent (breaks referential transparency)
matthewleon opened this issue · comments
Every time I run CTR encryption in GHCi, I get a different output...
*Main> encryptCTR (initAES ("YELLOW SUBMARINE" :: ByteString)) ("" :: ByteString) "something"
"\206\174\US\210v%@\188\DEL"
*Main> encryptCTR (initAES ("YELLOW SUBMARINE" :: ByteString)) ("" :: ByteString) "something"
"\210\142\144\179\DC3|M\\\132"
*Main> encryptCTR (initAES ("YELLOW SUBMARINE" :: ByteString)) ("" :: ByteString) "something"
"V\215\DEL\137\193\227f\235\226"
The problem seems to be in keystream generation:
*Main> genCTR (initAES ("YELLOW SUBMARINE" :: ByteString)) ("" :: ByteString) 32
"\152X\254\176\238\135\194\b@\150c\US\149\234\242\SI!R\255\SOH\253\208\182\170\176J\218s\ETX\239\161\191"
*Main> genCTR (initAES ("YELLOW SUBMARINE" :: ByteString)) ("" :: ByteString) 32
"\247\165\EOT\184\156\182\234\152\SO\222\225\244j\197C\207W\136\210\133Aa\166B\226\215ZB;\145\NUL{"
an AES IV is 16 bytes, and you're giving a 0 bytes IV. so basically it used random piece of memory, which is why you got random output. use crypto-cipher-types:
ctrCombine :: cipher -> IV cipher -> ByteString -> ByteString
which doesn't allow this.
Hi Vincent. I appreciate the clarification. Nevertheless, it seems to me that this still is something that shouldn't happen in safe code. Either an error should be thrown or the type signature for the CTR functions should be tightened, no?