Search code examples
rubyencryptioncryptographyaes

AES 128 CTR Mode in Ruby


I'm trying to decrypt some cipher text in CBC and CTR mode. The IV is said to be the first 16 bytes of the cipher text. I wrote this function in Ruby to solve it and with CBC, I got the correct results but as soon as I changed the mode to CTR, I get a random string of bytes.

This post and this post ask similar questions, but neither were using the correct IV text and I've check mine multiple times.

def decrypt(key, cipher, mode=:CBC)
  k = [key].pack('H*')
  iv = [cipher.scan(/../).first(16).join].pack('H*')
  c = [cipher].pack('H*')

  aes = OpenSSL::Cipher::AES.new(128, mode)
  aes.decrypt
  aes.iv = iv
  aes.key = k
  aes.update(c) + aes.final
end

With mode=CBC (Correct with disregared first few bytes):

decrypt('140b41b22a29beb4061bda66b6747e14', '4ca00ff4c898d61e1edbf1800618fb2828a226d160dad07883d04e008a7897ee2e4b7465d5290d0c0e6c6822236e1daafb94ffe0c5da05d9476be028ad7c1d81')
=> "LQ\xFCXTr@\t\xC7\eb\x0Ex\xB3\nQBasic CBC mode encryption needs padding."

With mode=CTR:

decrypt('36f18357be4dbd77f050515c73fcf9f2', '69dda8455c7dd4254bf353b773304eec0ec7702330098ce7f7520d1cbbb20fc388d1b0adb5054dbd7370849dbf0b88d393f252e764f1f5f7ad97ef79d59ce29f5f51eeca32eabedd9afa9329', :CTR)
=> "$N\x8AF\x01\e<\xA7\x9C\xCD;\xDF\xBB\xA28@\xF36\xA2\xFB\xEC`\xA5z\xE5\x02\xFA\xF5v\xDC\xE6};@\x8B:\xB9\x91\xCAj\xB8\x95\x04\x89J\xF6J.\xA0\xCC\xDFFvx\"Z_\b\x0E~[\x1F\x92+&U\xEB\x9E\xE0\xA7}\r\xC9Y?\xB2"

Solution

  • Thanks to Maarten's help in the comments above, I was able to refine my method to not include the IV in the cipher text when decrypting.

    def decrypt(key, cipher, mode=:CBC)
      k = [key].pack('H*')
      bytes = cipher.scan(/../)
      iv = [bytes[0..15].join].pack('H*')
      c = [bytes[16..-1].join].pack('H*')
    
      aes = OpenSSL::Cipher::AES128.new(mode)
      aes.decrypt
      aes.iv = iv
      aes.key = k
      aes.update(c) + aes.final
    end