Skip to content

Instantly share code, notes, and snippets.

@bglusman
Last active March 26, 2017 16:58
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bglusman/7e1df9efad80845977b60d44d335f3df to your computer and use it in GitHub Desktop.
Save bglusman/7e1df9efad80845977b60d44d335f3df to your computer and use it in GitHub Desktop.
simple working ruby-encryption to elixir-decryption (DO NOT USE a zero IV for real)
defmodule Decrypt do
@iv String.duplicate("0", 16)
def unpad(data) do
to_remove = :binary.last(data)
:binary.part(data, 0, byte_size(data) - to_remove)
end
def decrypt(data, key) do
IO.puts "WOrking to decrypt #{data} using #{key}"
padded = :crypto.block_decrypt(:aes_cbc256, key, @iv, :base64.decode(data))
unpad(padded)
end
end
#!/usr/bin/env ruby
require "openssl"
require 'digest/sha2'
require 'base64'
alg = "AES-256-CBC"
key = ARGV[0]
iv = "0" * 16
key64 = [key].pack('m')
raise 'Key Error' if(key.nil? or iv.size != 16)
aes = OpenSSL::Cipher::Cipher.new(alg)
aes.encrypt
aes.key = key
aes.iv = iv
cipher = ""
cipher << aes.update(ARGV[1])
cipher << aes.final
cipher64 = [cipher].pack('m')
puts cipher64
@ntrepid8
Copy link

Some of the issues with IV handling here may be due to differences in string handling. The IV here in elixir isn't really 0:

iex(4)> << i::integer-128 >> =  String.duplicate("0", 16)
"0000000000000000"
iex(5)> i
64053151420411946063694043751862251568

A zero IV would look more like this I think:

iex(14)> l = << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 >>
<<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>
iex(15)> byte_size l
16

I'm not sure exactly what the ruby string handling would do in this case.

What would happen if you used random bytes instead?

iex(9)> iv = :crypto.strong_rand_bytes(16)
<<18, 172, 218, 135, 230, 11, 229, 41, 173, 3, 29, 89, 236, 68, 178, 229>>
iex(10)> << j::integer-128 >> = iv         
<<18, 172, 218, 135, 230, 11, 229, 41, 173, 3, 29, 89, 236, 68, 178, 229>>
iex(11)> j
24823611316087944187846819446897554149

If you needed to transport the IV as a string you can base64 encode it just like the cipher-text.

@bglusman
Copy link
Author

@ntrepid8 I think actually all the issues I was having were a version of the same issues I had with IV, namely, not knowing the right size and not checking my size properly... all my successes were with an exactly 256 bit key in both ruby and elixir, "10000000000000010000000000000001" but then I tried to use my "real" key, and it looked right but Erlang would error when more than 256 bits in key, without saying why it was erroring... I think wrappers in ExCrypto should maybe have two versions, a regular version that enforces same requirements but checks parameters and raises meaningful errors if wrong iv or key length, and a decrypt! and encrypt! version that accept longer keys and iv's but just take the first 256 and 128 bits respectively, and only error if they're too SHORT... or we could invert that, as long as they're reasonably documented etc. I may start working on that now, just forked ExCrypto, but the 256-gcm version is currently the only thing supported, so perhaps I'll make algorithm an optional arg defaulting to 256-gcm and make a new version for 256-CBC, and if others want to add other algorithms they'll have a clear path to follow?

@bglusman
Copy link
Author

Oh, and yes, for sure typically random IV and base64 encoding it makes total sense, that's approx what ruby does, but for decrypting obviously random doesn't work, and in either case it's good to be able to control it... I'm considering making it a SHA1 of something already unique about the data so I can avoid shipping around the IV also and just have a convention, but we'll see....

Oh and yes, I was aware it wasn't really a zero iv, it was just meant to be simple and the same in both languages, not necessarily have any special properties.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment