lib/aes.ex

defmodule CA.AES do

    def e(x,y),       do: :erlang.element(x,y)
    def privat(name), do: e(3,:public_key.pem_entry_decode(readPEM("priv/certs/",name)))
    def public(name), do: e(3,e(8, e(2, :public_key.pem_entry_decode(readPEM("priv/certs/",name)))))
    def readPEM(folder, name),     do: hd(:public_key.pem_decode(e(2, :file.read_file(folder <> name))))
    def shared(pub, key, scheme),  do: :crypto.compute_key(:ecdh, pub, key, scheme)

    def decryptAES256ECB(data, key, iv \\ :crypto.strong_rand_bytes(16)) do
        :crypto.crypto_one_time(:aes_256_ecb,key,iv,data,[{:encrypt,false}])
    end

    def decryptAES256CBC(data, key, iv \\ :crypto.strong_rand_bytes(16)) do
        :crypto.crypto_one_time(:aes_256_cbc,key,iv,data,[{:encrypt,false}])
    end

    def decryptAES256GCM(data, key, iv \\ :crypto.strong_rand_bytes(16)) do
        <<iv::binary-16, tag::binary-16, bin::binary>> = data
        :crypto.crypto_one_time_aead(:aes_256_gcm, key, iv, data, "AES256GCM", tag, false)
    end

    def decryptAES256CCM(data, key, iv \\ :crypto.strong_rand_bytes(16)) do
        <<iv::binary-16, tag::binary-16, bin::binary>> = data
        :crypto.crypto_one_time_aead(:aes_256_ccm, key, iv, data, "AES256CCM", tag, false)
    end

    def encryptAES256ECB(data, key, iv \\ :crypto.strong_rand_bytes(16)) do
        :crypto.crypto_one_time(:aes_256_ecb,key,iv,data,[{:encrypt,true}])
    end

    def encryptAES256CBC(data, key, iv \\ :crypto.strong_rand_bytes(16)) do
        :crypto.crypto_one_time(:aes_256_cbc,key,iv,data,[{:encrypt,true}])
    end

    def encryptAES256GCM(data, key, iv \\ :crypto.strong_rand_bytes(16)) do
        {cipher, tag} = :crypto.crypto_one_time_aead(:aes_256_gcm, key, iv, data, "AES256GCM", true)
        iv <> tag <> cipher
    end

    def encryptAES256CCM(data, key, iv \\ :crypto.strong_rand_bytes(16)) do
        {cipher, tag} = :crypto.crypto_one_time_aead(:aes_256_ccm, key, iv, data, "AES256CCM", true)
        iv <> tag <> cipher
    end

    # public API is ASN.1 based

    def encrypt(crypto_codec, data, key, iv \\ :crypto.strong_rand_bytes(16))
    def encrypt(:'id-aes256-ECB', data, key, iv), do: encryptAES256ECB(data, key, iv)
    def encrypt(:'id-aes256-CBC', data, key, iv), do: encryptAES256CBC(data, key, iv)
    def encrypt(:'id-aes256-GCM', data, key, iv), do: encryptAES256GCM(data, key, iv)
    def encrypt(:'id-aes256-CCM', data, key, iv), do: encryptAES256CCM(data, key, iv)

    def decrypt(crypto_codec, data, key, iv \\ :crypto.strong_rand_bytes(16))
    def decrypt(:'id-aes256-ECB', data, key, iv), do: decryptAES256ECB(data, key, iv)
    def decrypt(:'id-aes256-CBC', data, key, iv), do: decryptAES256CBC(data, key, iv)
    def decrypt(:'id-aes256-GCM', data, key, iv), do: decryptAES256GCM(data, key, iv)
    def decrypt(:'id-aes256-CCM', data, key, iv), do: decryptAES256CCM(data, key, iv)

    def testSMIME() do
        {:ok,base} = :file.read_file "priv/encrypted.txt" ; [_,s] = :string.split base, "\n\n"
        :'CryptographicMessageSyntax-2010'.decode(:ContentInfo, :base64.decode(s))
    end

    def test() do
      [
        check_SECP384R1_GCM256(),
        check_X25519_GCM256(),
        check_C2PNB368w1_GCM256(),
        check_BrainPoolP512t1_GCM256(),
        check_BrainPoolP512t1_GCM256(),
        check_SECT571_GCM256(),
        check_X448_GCM256(),
        check_X448_CBC256(),
        check_X448_ECB256(),
      ]
       :ok
    end

    def check_SECP384R1_GCM256() do # SECP384r1
        scheme = :secp384r1
        aliceP = public "client.pem"
        aliceK = privat "client.key"
        maximP = public "server.pem"
        maximK = privat "server.key"
        maximS = :binary.part(shared(aliceP,maximK,scheme),0,32)
        aliceS = :binary.part(shared(maximP,aliceK,scheme),0,32)
        iv = :crypto.strong_rand_bytes(16)
        x = encrypt(:'id-aes256-GCM', "Success!", maximS, iv)
        "Success!" == decrypt(:'id-aes256-GCM', x, aliceS, iv)
        :ok
    end

    def check_X25519_GCM256() do # X25519
        scheme = :x25519
        {aliceP,aliceK} = :crypto.generate_key(:ecdh, scheme)
        {maximP,maximK} = :crypto.generate_key(:ecdh, scheme)
        maximS = shared(aliceP,maximK,scheme)
        aliceS = shared(maximP,aliceK,scheme)
        iv = :crypto.strong_rand_bytes(16)
        x = encrypt(:'id-aes256-GCM', "Success!", maximS, iv)
        "Success!" == decrypt(:'id-aes256-GCM', x, aliceS, iv)
        :ok
    end

    def check_C2PNB368w1_GCM256() do # C2PNB368w1
        scheme = :c2pnb368w1
        {aliceP,aliceK} = :crypto.generate_key(:ecdh, scheme)
        {maximP,maximK} = :crypto.generate_key(:ecdh, scheme)
        maximS = :binary.part(shared(aliceP,maximK,scheme),0,32)
        aliceS = :binary.part(shared(maximP,aliceK,scheme),0,32)
        iv = :crypto.strong_rand_bytes(16)
        x = encrypt(:'id-aes256-GCM', "Success!", maximS, iv)
        "Success!" == decrypt(:'id-aes256-GCM', x, aliceS, iv)
        :ok
    end

    def check_BrainPoolP512t1_GCM256() do # BrainPoolP512t1
        scheme = :brainpoolP512t1
        {aliceP,aliceK} = :crypto.generate_key(:ecdh, scheme)
        {maximP,maximK} = :crypto.generate_key(:ecdh, scheme)
        maximS = :binary.part(shared(aliceP,maximK,scheme),0,32)
        aliceS = :binary.part(shared(maximP,aliceK,scheme),0,32)
        iv = :crypto.strong_rand_bytes(16)
        x = encrypt(:'id-aes256-GCM', "Success!", maximS, iv)
        "Success!" == decrypt(:'id-aes256-GCM', x, aliceS, iv)
        :ok
    end

    def check_BrainPoolP512t1_GCM256() do # BrainPoolP512t1
        scheme = :brainpoolP512t1
        {aliceP,aliceK} = :crypto.generate_key(:ecdh, scheme)
        {maximP,maximK} = :crypto.generate_key(:ecdh, scheme)
        maximS = :binary.part(shared(aliceP,maximK,scheme),0,32)
        aliceS = :binary.part(shared(maximP,aliceK,scheme),0,32)
        iv = :crypto.strong_rand_bytes(16)
        x = encrypt(:'id-aes256-GCM', "Success!", maximS, iv)
        "Success!" == decrypt(:'id-aes256-GCM', x, aliceS, iv)
        :ok
    end

    def check_SECT571_GCM256() do # SECT571r1
        scheme = :sect571r1
        {aliceP,aliceK} = :crypto.generate_key(:ecdh, scheme)
        {maximP,maximK} = :crypto.generate_key(:ecdh, scheme)
        maximS = :binary.part(shared(aliceP,maximK,scheme),0,32)
        aliceS = :binary.part(shared(maximP,aliceK,scheme),0,32)
        iv = :crypto.strong_rand_bytes(16)
        x = encrypt(:'id-aes256-GCM', "Success!", maximS, iv)
        "Success!" == decrypt(:'id-aes256-GCM', x, aliceS, iv)
        :ok
    end

    def check_X448_GCM256() do # X488
        scheme = :x448
        {aliceP,aliceK} = :crypto.generate_key(:ecdh, scheme)
        {maximP,maximK} = :crypto.generate_key(:ecdh, scheme)
        maximS = :binary.part(shared(aliceP,maximK,scheme),0,32)
        aliceS = :binary.part(shared(maximP,aliceK,scheme),0,32)
        iv = :crypto.strong_rand_bytes(16)
        x = encrypt(:'id-aes256-GCM', "Success!", maximS, iv)
        "Success!" == decrypt(:'id-aes256-GCM', x, aliceS, iv)
        :ok
    end

    def check_X448_CBC256() do # X488
        scheme = :x448
        {aliceP,aliceK} = :crypto.generate_key(:ecdh, scheme)
        {maximP,maximK} = :crypto.generate_key(:ecdh, scheme)
        maximS = :binary.part(shared(aliceP,maximK,scheme),0,32)
        aliceS = :binary.part(shared(maximP,aliceK,scheme),0,32)
        x = encrypt(:'id-aes256-CBC', "Success!", maximS)
        "Success!" == decrypt(:'id-aes256-CBC', x, aliceS)
        :ok
    end

    def check_X448_ECB256() do # X488
        scheme = :x448
        {aliceP,aliceK} = :crypto.generate_key(:ecdh, scheme)
        {maximP,maximK} = :crypto.generate_key(:ecdh, scheme)
        maximS = :binary.part(shared(aliceP,maximK,scheme),0,32)
        aliceS = :binary.part(shared(maximP,aliceK,scheme),0,32)
        x = encrypt(:'id-aes256-ECB', "Success!", maximS)
        "Success!" == decrypt(:'id-aes256-ECB', x, aliceS)
        :ok
    end


end