diff options
Diffstat (limited to 'lib/ssl/src/ssl_cipher.erl')
-rw-r--r-- | lib/ssl/src/ssl_cipher.erl | 784 |
1 files changed, 784 insertions, 0 deletions
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl new file mode 100644 index 0000000000..3d3d11b7f3 --- /dev/null +++ b/lib/ssl/src/ssl_cipher.erl @@ -0,0 +1,784 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Help functions for handling the SSL ciphers +%% +%%---------------------------------------------------------------------- + +-module(ssl_cipher). + +-include("ssl_internal.hrl"). +-include("ssl_record.hrl"). +-include("ssl_cipher.hrl"). +-include("ssl_debug.hrl"). + +-export([security_parameters/2, suite_definition/1, + decipher/4, cipher/4, + suite/1, suites/1, + openssl_suite/1, openssl_suite_name/1]). + +-compile(inline). + +%%-------------------------------------------------------------------- +%% Function: security_parameters(CipherSuite, SecParams) -> +%% #security_parameters{} +%% +%% CipherSuite - as defined in ssl_cipher.hrl +%% SecParams - #security_parameters{} +%% +%% Description: Returns a security parameters record where the +%% cipher values has been updated according to <CipherSuite> +%%------------------------------------------------------------------- +security_parameters(CipherSuite, SecParams) -> + { _, Cipher, Hash, Exportable} = suite_definition(CipherSuite), + SecParams#security_parameters{ + cipher_suite = CipherSuite, + bulk_cipher_algorithm = bulk_cipher_algorithm(Cipher), + cipher_type = type(Cipher), + key_size = effective_key_bits(Cipher), + expanded_key_material_length = expanded_key_material(Cipher), + key_material_length = key_material(Cipher), + iv_size = iv_size(Cipher), + mac_algorithm = mac_algorithm(Hash), + hash_size = hash_size(Hash), + exportable = Exportable}. + +%%-------------------------------------------------------------------- +%% Function: cipher(Method, CipherState, Mac, Data) -> +%% {Encrypted, UpdateCipherState} +%% +%% Method - integer() (as defined in ssl_cipher.hrl) +%% CipherState, UpdatedCipherState - #cipher_state{} +%% Data, Encrypted - binary() +%% +%% Description: Encrypts the data and the mac using method, updating +%% the cipher state +%%------------------------------------------------------------------- +cipher(?NULL, CipherState, <<>>, Fragment) -> + GenStreamCipherList = [Fragment, <<>>], + {GenStreamCipherList, CipherState}; +cipher(?RC4, CipherState, Mac, Fragment) -> + State0 = case CipherState#cipher_state.state of + undefined -> crypto:rc4_set_key(CipherState#cipher_state.key); + S -> S + end, + GenStreamCipherList = [Fragment, Mac], + + ?DBG_HEX(GenStreamCipherList), + ?DBG_HEX(State0), + {State1, T} = crypto:rc4_encrypt_with_state(State0, GenStreamCipherList), + ?DBG_HEX(T), + {T, CipherState#cipher_state{state = State1}}; +cipher(?DES, CipherState, Mac, Fragment) -> + block_cipher(fun(Key, IV, T) -> + crypto:des_cbc_encrypt(Key, IV, T) + end, block_size(des_cbc), CipherState, Mac, Fragment); +cipher(?DES40, CipherState, Mac, Fragment) -> + block_cipher(fun(Key, IV, T) -> + crypto:des_cbc_encrypt(Key, IV, T) + end, block_size(des_cbc), CipherState, Mac, Fragment); +cipher(?'3DES', CipherState, Mac, Fragment) -> + block_cipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) -> + crypto:des3_cbc_encrypt(K1, K2, K3, IV, T) + end, block_size(des_cbc), CipherState, Mac, Fragment); +cipher(?AES, CipherState, Mac, Fragment) -> + block_cipher(fun(Key, IV, T) when byte_size(Key) =:= 16 -> + crypto:aes_cbc_128_encrypt(Key, IV, T); + (Key, IV, T) when byte_size(Key) =:= 32 -> + crypto:aes_cbc_256_encrypt(Key, IV, T) + end, block_size(aes_128_cbc), CipherState, Mac, Fragment); +%% cipher(?IDEA, CipherState, Mac, Fragment) -> +%% block_cipher(fun(Key, IV, T) -> +%% crypto:idea_cbc_encrypt(Key, IV, T) +%% end, block_size(idea_cbc), CipherState, Mac, Fragment); +cipher(?RC2, CipherState, Mac, Fragment) -> + block_cipher(fun(Key, IV, T) -> + crypto:rc2_40_cbc_encrypt(Key, IV, T) + end, block_size(rc2_cbc_40), CipherState, Mac, Fragment). + +block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, + Mac, Fragment) -> + TotSz = byte_size(Mac) + erlang:iolist_size(Fragment) + 1, + {PaddingLength, Padding} = get_padding(TotSz, BlockSz), + L = [Fragment, Mac, PaddingLength, Padding], + ?DBG_HEX(Key), + ?DBG_HEX(IV), + ?DBG_HEX(L), + T = Fun(Key, IV, L), + ?DBG_HEX(T), + NextIV = next_iv(T, IV), + {T, CS0#cipher_state{iv=NextIV}}. + +%%-------------------------------------------------------------------- +%% Function: decipher(Method, CipherState, Mac, Data) -> +%% {Decrypted, UpdateCipherState} +%% +%% Method - integer() (as defined in ssl_cipher.hrl) +%% CipherState, UpdatedCipherState - #cipher_state{} +%% Data, Encrypted - binary() +%% +%% Description: Decrypts the data and the mac using method, updating +%% the cipher state +%%------------------------------------------------------------------- +decipher(?NULL, _HashSz, CipherState, Fragment) -> + {Fragment, <<>>, CipherState}; +decipher(?RC4, HashSz, CipherState, Fragment) -> + ?DBG_TERM(CipherState#cipher_state.key), + State0 = case CipherState#cipher_state.state of + undefined -> crypto:rc4_set_key(CipherState#cipher_state.key); + S -> S + end, + ?DBG_HEX(State0), + ?DBG_HEX(Fragment), + {State1, T} = crypto:rc4_encrypt_with_state(State0, Fragment), + ?DBG_HEX(T), + GSC = generic_stream_cipher_from_bin(T, HashSz), + #generic_stream_cipher{content=Content, mac=Mac} = GSC, + {Content, Mac, CipherState#cipher_state{state=State1}}; +decipher(?DES, HashSz, CipherState, Fragment) -> + block_decipher(fun(Key, IV, T) -> + crypto:des_cbc_decrypt(Key, IV, T) + end, CipherState, HashSz, Fragment); +decipher(?DES40, HashSz, CipherState, Fragment) -> + block_decipher(fun(Key, IV, T) -> + crypto:des_cbc_decrypt(Key, IV, T) + end, CipherState, HashSz, Fragment); +decipher(?'3DES', HashSz, CipherState, Fragment) -> + block_decipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) -> + crypto:des3_cbc_decrypt(K1, K2, K3, IV, T) + end, CipherState, HashSz, Fragment); +decipher(?AES, HashSz, CipherState, Fragment) -> + block_decipher(fun(Key, IV, T) when byte_size(Key) =:= 16 -> + crypto:aes_cbc_128_decrypt(Key, IV, T); + (Key, IV, T) when byte_size(Key) =:= 32 -> + crypto:aes_cbc_256_decrypt(Key, IV, T) + end, CipherState, HashSz, Fragment); +%% decipher(?IDEA, HashSz, CipherState, Fragment) -> +%% block_decipher(fun(Key, IV, T) -> +%% crypto:idea_cbc_decrypt(Key, IV, T) +%% end, CipherState, HashSz, Fragment); +decipher(?RC2, HashSz, CipherState, Fragment) -> + block_decipher(fun(Key, IV, T) -> + crypto:rc2_40_cbc_decrypt(Key, IV, T) + end, CipherState, HashSz, Fragment). + +block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0, + HashSz, Fragment) -> + ?DBG_HEX(Key), + ?DBG_HEX(IV), + ?DBG_HEX(Fragment), + T = Fun(Key, IV, Fragment), + ?DBG_HEX(T), + GBC = generic_block_cipher_from_bin(T, HashSz), + ok = check_padding(GBC), %% TODO kolla ocks�... + Content = GBC#generic_block_cipher.content, + Mac = GBC#generic_block_cipher.mac, + CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)}, + {Content, Mac, CipherState1}. + +%%-------------------------------------------------------------------- +%% Function: suites(Version) -> [Suite] +%% +%% Version = version() +%% Suite = binary() from ssl_cipher.hrl +%% +%% Description: Returns a list of supported cipher suites. +%%-------------------------------------------------------------------- +suites({3, 0}) -> + ssl_ssl3:suites(); +suites({3, N}) when N == 1; N == 2 -> + ssl_tls1:suites(). + +%%-------------------------------------------------------------------- +%% Function: suite_definition(CipherSuite) -> +%% {KeyExchange, Cipher, Hash, Exportable} +%% +%% +%% CipherSuite - as defined in ssl_cipher.hrl +%% KeyExchange - rsa | dh_dss | dh_rsa | dh_anon | dhe_dss | dhe_rsa +%% krb5 | *_export (old ssl) +%% Cipher - null | rc4_128 | idea_cbc | des_cbc | '3des_ede_cbc' +%% des40_cbc | dh_dss | aes_128_cbc | aes_256_cbc | +%% rc2_cbc_40 | rc4_40 +%% Hash - null | md5 | sha +%% Exportable - export | no_export | ignore(?) +%% +%% Description: Returns a security parameters record where the +%% cipher values has been updated according to <CipherSuite> +%% Note: since idea is unsupported on the openssl version used by +%% crypto (as of OTP R12B), we've commented away the idea stuff +%%------------------------------------------------------------------- +%% TLS v1.1 suites +suite_definition(?TLS_NULL_WITH_NULL_NULL) -> + {null, null, null, ignore}; +suite_definition(?TLS_RSA_WITH_NULL_MD5) -> + {rsa, null, md5, ignore}; +suite_definition(?TLS_RSA_WITH_NULL_SHA) -> + {rsa, null, sha, ignore}; +suite_definition(?TLS_RSA_WITH_RC4_128_MD5) -> % ok + {rsa, rc4_128, md5, no_export}; +suite_definition(?TLS_RSA_WITH_RC4_128_SHA) -> % ok + {rsa, rc4_128, sha, no_export}; +%% suite_definition(?TLS_RSA_WITH_IDEA_CBC_SHA) -> % unsupported +%% {rsa, idea_cbc, sha, no_export}; +suite_definition(?TLS_RSA_WITH_DES_CBC_SHA) -> % ok + {rsa, des_cbc, sha, no_export}; +suite_definition(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) -> + {rsa, '3des_ede_cbc', sha, no_export}; +suite_definition(?TLS_DH_DSS_WITH_DES_CBC_SHA) -> + {dh_dss, des_cbc, sha, no_export}; +suite_definition(?TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA) -> + {dh_dss, '3des_ede_cbc', sha, no_export}; +suite_definition(?TLS_DH_RSA_WITH_DES_CBC_SHA) -> + {dh_rsa, des_cbc, sha, no_export}; +suite_definition(?TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA) -> + {dh_rsa, '3des_ede_cbc', sha, no_export}; +suite_definition(?TLS_DHE_DSS_WITH_DES_CBC_SHA) -> + {dhe_dss, des_cbc, sha, no_export}; +suite_definition(?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) -> + {dhe_dss, '3des_ede_cbc', sha, no_export}; +suite_definition(?TLS_DHE_RSA_WITH_DES_CBC_SHA) -> + {dhe_rsa, des_cbc, sha, no_export}; +suite_definition(?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) -> + {dhe_rsa, '3des_ede_cbc', sha, no_export}; +suite_definition(?TLS_DH_anon_WITH_RC4_128_MD5) -> + {dh_anon, rc4_128, md5, no_export}; +suite_definition(?TLS_DH_anon_WITH_DES_CBC_SHA) -> + {dh_anon, des40_cbc, sha, no_export}; +suite_definition(?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA) -> + {dh_anon, '3des_ede_cbc', sha, no_export}; + +%%% TSL V1.1 AES suites +suite_definition(?TLS_RSA_WITH_AES_128_CBC_SHA) -> % ok + {rsa, aes_128_cbc, sha, ignore}; +suite_definition(?TLS_DH_DSS_WITH_AES_128_CBC_SHA) -> + {dh_dss, aes_128_cbc, sha, ignore}; +suite_definition(?TLS_DH_RSA_WITH_AES_128_CBC_SHA) -> + {dh_rsa, aes_128_cbc, sha, ignore}; +suite_definition(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) -> + {dhe_dss, aes_128_cbc, sha, ignore}; +suite_definition(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA) -> + {dhe_rsa, aes_128_cbc, sha, ignore}; +suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA) -> + {dh_anon, aes_128_cbc, sha, ignore}; +suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA) -> % ok + {rsa, aes_256_cbc, sha, ignore}; +suite_definition(?TLS_DH_DSS_WITH_AES_256_CBC_SHA) -> + {dh_dss, aes_256_cbc, sha, ignore}; +suite_definition(?TLS_DH_RSA_WITH_AES_256_CBC_SHA) -> + {dh_rsa, aes_256_cbc, sha, ignore}; +suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) -> + {dhe_dss, aes_256_cbc, sha, ignore}; +suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) -> + {dhe_rsa, aes_256_cbc, sha, ignore}; +suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) -> + {dh_anon, aes_256_cbc, sha, ignore}; + +%% TSL V1.1 KRB SUITES +suite_definition(?TLS_KRB5_WITH_DES_CBC_SHA) -> + {krb5, des_cbc, sha, ignore}; +suite_definition(?TLS_KRB5_WITH_3DES_EDE_CBC_SHA) -> + {krb5, '3des_ede_cbc', sha, ignore}; +suite_definition(?TLS_KRB5_WITH_RC4_128_SHA) -> + {krb5, rc4_128, sha, ignore}; +%% suite_definition(?TLS_KRB5_WITH_IDEA_CBC_SHA) -> +%% {krb5, idea_cbc, sha, ignore}; +suite_definition(?TLS_KRB5_WITH_DES_CBC_MD5) -> + {krb5, des_cbc, md5, ignore}; +suite_definition(?TLS_KRB5_WITH_3DES_EDE_CBC_MD5) -> + {krb5, '3des_ede_cbc', md5, ignore}; +suite_definition(?TLS_KRB5_WITH_RC4_128_MD5) -> + {krb5, rc4_128, md5, ignore}; +%% suite_definition(?TLS_KRB5_WITH_IDEA_CBC_MD5) -> +%% {krb5, idea_cbc, md5, ignore}; + +suite_definition(?TLS_RSA_EXPORT1024_WITH_RC4_56_MD5) -> + {rsa, rc4_56, md5, export}; +suite_definition(?TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5) -> + {rsa, rc2_cbc_56, md5, export}; +suite_definition(?TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA) -> + {rsa, des_cbc, sha, export}; +suite_definition(?TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA) -> + {dhe_dss, des_cbc, sha, export}; +suite_definition(?TLS_RSA_EXPORT1024_WITH_RC4_56_SHA) -> + {rsa, rc4_56, sha, export}; +suite_definition(?TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA) -> + {dhe_dss, rc4_56, sha, export}; +suite_definition(?TLS_DHE_DSS_WITH_RC4_128_SHA) -> + {dhe_dss, rc4_128, sha, export}; + +%% Export suites TLS 1.0 OR SSLv3-only servers. +suite_definition(?TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA) -> + {krb5_export, des40_cbc, sha, export}; +suite_definition(?TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA) -> + {krb5_export, rc2_cbc_40, sha, export}; +suite_definition(?TLS_KRB5_EXPORT_WITH_RC4_40_SHA) -> + {krb5_export, des40_cbc, sha, export}; +suite_definition(?TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5) -> + {krb5_export, des40_cbc, md5, export}; +suite_definition(?TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5) -> + {krb5_export, rc2_cbc_40, md5, export}; +suite_definition(?TLS_KRB5_EXPORT_WITH_RC4_40_MD5) -> + {krb5_export, rc2_cbc_40, md5, export}; +suite_definition(?TLS_RSA_EXPORT_WITH_RC4_40_MD5) -> % ok + {rsa, rc4_40, md5, export}; +suite_definition(?TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5) -> % ok + {rsa, rc2_cbc_40, md5, export}; +suite_definition(?TLS_RSA_EXPORT_WITH_DES40_CBC_SHA) -> + {rsa, des40_cbc, sha, export}; +suite_definition(?TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA) -> + {dh_dss, des40_cbc, sha, export}; +suite_definition(?TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA) -> + {dh_rsa, des40_cbc, sha, export}; +suite_definition(?TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA) -> + {dhe_dss, des40_cbc, sha, export}; +suite_definition(?TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA) -> + {dhe_rsa, des40_cbc, sha, export}; +suite_definition(?TLS_DH_anon_EXPORT_WITH_RC4_40_MD5) -> + {dh_anon, rc4_40, md5, export}; +suite_definition(?TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA) -> + {dh_anon, des40_cbc, sha, export}. + +%% TLS v1.1 suites +suite({rsa, null, md5, ignore}) -> + ?TLS_RSA_WITH_NULL_MD5; +suite({rsa, null, sha, ignore}) -> + ?TLS_RSA_WITH_NULL_SHA; +suite({rsa, rc4_128, md5, no_export}) -> + ?TLS_RSA_WITH_RC4_128_MD5; +suite({rsa, rc4_128, sha, no_export}) -> + ?TLS_RSA_WITH_RC4_128_SHA; +%% suite({rsa, idea_cbc, sha, no_export}) -> +%% ?TLS_RSA_WITH_IDEA_CBC_SHA; +suite({rsa, des_cbc, sha, no_export}) -> + ?TLS_RSA_WITH_DES_CBC_SHA; +suite({rsa, '3des_ede_cbc', sha, no_export}) -> + ?TLS_RSA_WITH_3DES_EDE_CBC_SHA; +suite({dh_dss, des_cbc, sha, no_export}) -> + ?TLS_DH_DSS_WITH_DES_CBC_SHA; +suite({dh_dss, '3des_ede_cbc', sha, no_export}) -> + ?TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA; +suite({dh_rsa, des_cbc, sha, no_export}) -> + ?TLS_DH_RSA_WITH_DES_CBC_SHA; +suite({dh_rsa, '3des_ede_cbc', sha, no_export}) -> + ?TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA; +suite({dhe_dss, des_cbc, sha, no_export}) -> + ?TLS_DHE_DSS_WITH_DES_CBC_SHA; +suite({dhe_dss, '3des_ede_cbc', sha, no_export}) -> + ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA; +suite({dhe_rsa, des_cbc, sha, no_export}) -> + ?TLS_DHE_RSA_WITH_DES_CBC_SHA; +suite({dhe_rsa, '3des_ede_cbc', sha, no_export}) -> + ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA; +suite({dh_anon, rc4_128, md5, no_export}) -> + ?TLS_DH_anon_WITH_RC4_128_MD5; +suite({dh_anon, des40_cbc, sha, no_export}) -> + ?TLS_DH_anon_WITH_DES_CBC_SHA; +suite({dh_anon, '3des_ede_cbc', sha, no_export}) -> + ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA; + +%%% TSL V1.1 AES suites +suite({rsa, aes_128_cbc, sha, ignore}) -> + ?TLS_RSA_WITH_AES_128_CBC_SHA; +suite({dh_dss, aes_128_cbc, sha, ignore}) -> + ?TLS_DH_DSS_WITH_AES_128_CBC_SHA; +suite({dh_rsa, aes_128_cbc, sha, ignore}) -> + ?TLS_DH_RSA_WITH_AES_128_CBC_SHA; +suite({dhe_dss, aes_128_cbc, sha, ignore}) -> + ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA; +suite({dhe_rsa, aes_128_cbc, sha, ignore}) -> + ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA; +suite({dh_anon, aes_128_cbc, sha, ignore}) -> + ?TLS_DH_anon_WITH_AES_128_CBC_SHA; +suite({rsa, aes_256_cbc, sha, ignore}) -> + ?TLS_RSA_WITH_AES_256_CBC_SHA; +suite({dh_dss, aes_256_cbc, sha, ignore}) -> + ?TLS_DH_DSS_WITH_AES_256_CBC_SHA; +suite({dh_rsa, aes_256_cbc, sha, ignore}) -> + ?TLS_DH_RSA_WITH_AES_256_CBC_SHA; +suite({dhe_dss, aes_256_cbc, sha, ignore}) -> + ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA; +suite({dhe_rsa, aes_256_cbc, sha, ignore}) -> + ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA; +suite({dh_anon, aes_256_cbc, sha, ignore}) -> + ?TLS_DH_anon_WITH_AES_256_CBC_SHA; + +%% TSL V1.1 KRB SUITES +suite({krb5, des_cbc, sha, ignore}) -> + ?TLS_KRB5_WITH_DES_CBC_SHA; +suite({krb5_cbc, '3des_ede_cbc', sha, ignore}) -> + ?TLS_KRB5_WITH_3DES_EDE_CBC_SHA; +suite({krb5, rc4_128, sha, ignore}) -> + ?TLS_KRB5_WITH_RC4_128_SHA; +%% suite({krb5_cbc, idea_cbc, sha, ignore}) -> +%% ?TLS_KRB5_WITH_IDEA_CBC_SHA; +suite({krb5_cbc, md5, ignore}) -> + ?TLS_KRB5_WITH_DES_CBC_MD5; +suite({krb5_ede_cbc, des_cbc, md5, ignore}) -> + ?TLS_KRB5_WITH_3DES_EDE_CBC_MD5; +suite({krb5_128, rc4_128, md5, ignore}) -> + ?TLS_KRB5_WITH_RC4_128_MD5; +%% suite({krb5, idea_cbc, md5, ignore}) -> +%% ?TLS_KRB5_WITH_IDEA_CBC_MD5; + +%% Export suites TLS 1.0 OR SSLv3-only servers. +suite({rsa, rc4_40, md5, export}) -> + ?TLS_RSA_EXPORT_WITH_RC4_40_MD5; +suite({rsa, rc2_cbc_40, md5, export}) -> + ?TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5; +suite({rsa, des40_cbc, sha, export}) -> + ?TLS_RSA_EXPORT_WITH_DES40_CBC_SHA; +suite({rsa, rc4_56, md5, export}) -> + ?TLS_RSA_EXPORT1024_WITH_RC4_56_MD5; +suite({rsa, rc2_cbc_56, md5, export}) -> + ?TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5; +suite({rsa, des_cbc, sha, export}) -> + ?TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA; +suite({dhe_dss, des_cbc, sha, export}) -> + ?TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA; +suite({rsa, rc4_56, sha, export}) -> + ?TLS_RSA_EXPORT1024_WITH_RC4_56_SHA; +suite({dhe_dss, rc4_56, sha, export}) -> + ?TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA; +suite({dhe_dss, rc4_128, sha, export}) -> + ?TLS_DHE_DSS_WITH_RC4_128_SHA; +suite({krb5_export, des40_cbc, sha, export}) -> + ?TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA; +suite({krb5_export, rc2_cbc_40, sha, export}) -> + ?TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA; +suite({krb5_export, rc4_cbc_40, sha, export}) -> + ?TLS_KRB5_EXPORT_WITH_RC4_40_SHA; +suite({krb5_export, des40_cbc, md5, export}) -> + ?TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5; +suite({krb5_export, rc2_cbc_40, md5, export}) -> + ?TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5; +suite({krb5_export, rc4_cbc_40, md5, export}) -> + ?TLS_KRB5_EXPORT_WITH_RC4_40_MD5; +suite({rsa_export, rc4_cbc_40, md5, export}) -> + ?TLS_RSA_EXPORT_WITH_RC4_40_MD5; +suite({rsa_export, rc2_cbc_40, md5, export}) -> + ?TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5; +suite({rsa_export, des40_cbc, sha, export}) -> + ?TLS_RSA_EXPORT_WITH_DES40_CBC_SHA; +suite({dh_dss_export, des40_cbc, sha, export}) -> + ?TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA; +suite({dh_rsa_export, des40_cbc, sha, export}) -> + ?TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA; +suite({dhe_dss_export, des40_cbc, sha, export}) -> + ?TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA; +suite({dhe_rsa_export, des40_cbc, sha, export}) -> + ?TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA; +suite({dh_anon_export, rc4_40, md5, export}) -> + ?TLS_DH_anon_EXPORT_WITH_RC4_40_MD5; +suite({dh_anon_export, des40_cbc, sha, export}) -> + ?TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA. + + +%% translate constants <-> openssl-strings +%% TODO: Is there a pattern in the nameing +%% that is useable to make a nicer function defention? + +openssl_suite("DHE-RSA-AES256-SHA") -> + ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA; +openssl_suite("DHE-DSS-AES256-SHA") -> + ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA; +openssl_suite("AES256-SHA") -> + ?TLS_RSA_WITH_AES_256_CBC_SHA; +openssl_suite("EDH-RSA-DES-CBC3-SHA") -> + ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA; +openssl_suite("EDH-DSS-DES-CBC3-SHA") -> + ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA; +openssl_suite("DES-CBC3-SHA") -> + ?TLS_RSA_WITH_3DES_EDE_CBC_SHA; +openssl_suite("DHE-RSA-AES128-SHA") -> + ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA; +openssl_suite("DHE-DSS-AES128-SHA") -> + ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA; +openssl_suite("AES128-SHA") -> + ?TLS_RSA_WITH_AES_128_CBC_SHA; +%% TODO: Do we want to support this? +%% openssl_suite("DHE-DSS-RC4-SHA") -> +%% ?TLS_DHE_DSS_WITH_RC4_128_SHA; +%%openssl_suite("IDEA-CBC-SHA") -> +%% ?TLS_RSA_WITH_IDEA_CBC_SHA; +openssl_suite("RC4-SHA") -> + ?TLS_RSA_WITH_RC4_128_SHA; +openssl_suite("RC4-MD5") -> + ?TLS_RSA_WITH_RC4_128_MD5; +%% TODO: Do we want to support this? +openssl_suite("EXP1024-RC4-MD5") -> + ?TLS_RSA_EXPORT1024_WITH_RC4_56_MD5; +openssl_suite("EXP1024-RC2-CBC-MD5") -> + ?TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5; +openssl_suite("EXP1024-DES-CBC-SHA") -> + ?TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA; +openssl_suite("EXP1024-DHE-DSS-DES-CBC-SHA") -> + ?TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA; +openssl_suite("EXP1024-RC4-SHA") -> + ?TLS_RSA_EXPORT1024_WITH_RC4_56_SHA; +openssl_suite("EXP1024-DHE-DSS-RC4-SHA") -> + ?TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA; +openssl_suite("DHE-DSS-RC4-SHA") -> + ?TLS_DHE_DSS_WITH_RC4_128_SHA; + +openssl_suite("EDH-RSA-DES-CBC-SHA") -> + ?TLS_DHE_RSA_WITH_DES_CBC_SHA; +openssl_suite("DES-CBC-SHA") -> + ?TLS_RSA_WITH_DES_CBC_SHA; +openssl_suite("EXP-EDH-RSA-DES-CBC-SHA") -> + ?TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA; +openssl_suite("EXP-EDH-DSS-DES-CBC-SHA") -> + ?TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA; +openssl_suite("EXP-DES-CBC-SHA") -> + ?TLS_RSA_EXPORT_WITH_DES40_CBC_SHA; +openssl_suite("EXP-RC2-CBC-MD5") -> + ?TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5; +openssl_suite("EXP-RC4-MD5") -> + ?TLS_RSA_EXPORT_WITH_RC4_40_MD5. + +openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) -> + "DHE-RSA-AES256-SHA"; +openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) -> + "DHE-DSS-AES256-SHA"; +openssl_suite_name(?TLS_RSA_WITH_AES_256_CBC_SHA) -> + "AES256-SHA"; +openssl_suite_name(?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) -> + "EDH-RSA-DES-CBC3-SHA"; +openssl_suite_name(?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) -> + "EDH-DSS-DES-CBC3-SHA"; +openssl_suite_name(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) -> + "DES-CBC3-SHA"; +openssl_suite_name( ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA) -> + "DHE-RSA-AES128-SHA"; +openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) -> + "DHE-DSS-AES128-SHA"; +openssl_suite_name(?TLS_RSA_WITH_AES_128_CBC_SHA) -> + "AES128-SHA"; +%% openssl_suite_name(?TLS_RSA_WITH_IDEA_CBC_SHA) -> +%% "IDEA-CBC-SHA"; +openssl_suite_name(?TLS_RSA_WITH_RC4_128_SHA) -> + "RC4-SHA"; +openssl_suite_name(?TLS_RSA_WITH_RC4_128_MD5) -> + "RC4-MD5"; +openssl_suite_name(?TLS_DHE_RSA_WITH_DES_CBC_SHA) -> + "EDH-RSA-DES-CBC-SHA"; +openssl_suite_name(?TLS_RSA_WITH_DES_CBC_SHA) -> + "DES-CBC-SHA"; +openssl_suite_name(?TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA) -> + "EXP-EDH-RSA-DES-CBC-SHA"; +openssl_suite_name(?TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA) -> + "EXP-EDH-DSS-DES-CBC-SHA"; +openssl_suite_name(?TLS_RSA_EXPORT_WITH_DES40_CBC_SHA) -> + "EXP-DES-CBC-SHA"; +openssl_suite_name(?TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5) -> + "EXP-RC2-CBC-MD5"; +openssl_suite_name(?TLS_RSA_EXPORT_WITH_RC4_40_MD5) -> + "EXP-RC4-MD5"; + +openssl_suite_name(?TLS_RSA_EXPORT1024_WITH_RC4_56_MD5) -> + "EXP1024-RC4-MD5"; +openssl_suite_name(?TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5) -> + "EXP1024-RC2-CBC-MD5"; +openssl_suite_name(?TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA) -> + "EXP1024-DES-CBC-SHA"; +openssl_suite_name(?TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA) -> + "EXP1024-DHE-DSS-DES-CBC-SHA"; +openssl_suite_name(?TLS_RSA_EXPORT1024_WITH_RC4_56_SHA) -> + "EXP1024-RC4-SHA"; +openssl_suite_name(?TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA) -> + "EXP1024-DHE-DSS-RC4-SHA"; +openssl_suite_name(?TLS_DHE_DSS_WITH_RC4_128_SHA) -> + "DHE-DSS-RC4-SHA"; + +%% No oppenssl name +openssl_suite_name(Cipher) -> + suite_definition(Cipher). + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- + +bulk_cipher_algorithm(null) -> + ?NULL; +%% Not supported yet +%% bulk_cipher_algorithm(idea_cbc) -> +%% ?IDEA; +bulk_cipher_algorithm(Cipher) when Cipher == rc2_cbc_40; + Cipher == rc2_cbc_56 -> + ?RC2; +bulk_cipher_algorithm(Cipher) when Cipher == rc4_40; + Cipher == rc4_56; + Cipher == rc4_128 -> + ?RC4; +bulk_cipher_algorithm(des40_cbc) -> + ?DES40; +bulk_cipher_algorithm(des_cbc) -> + ?DES; +bulk_cipher_algorithm('3des_ede_cbc') -> + ?'3DES'; +bulk_cipher_algorithm(Cipher) when Cipher == aes_128_cbc; + Cipher == aes_256_cbc -> + ?AES. + +type(Cipher) when Cipher == null; + Cipher == rc4_40; + Cipher == rc4_56; + Cipher == rc4_128 -> + ?STREAM; + +type(Cipher) when Cipher == idea_cbc; + Cipher == rc2_cbc_40; + Cipher == rc2_cbc_56; + Cipher == des40_cbc; + Cipher == des_cbc; + Cipher == '3des_ede_cbc'; + Cipher == aes_128_cbc; + Cipher == aes_256_cbc -> + ?BLOCK. + +key_material(null) -> + 0; +key_material(Cipher) when Cipher == idea_cbc; + Cipher == rc4_128 -> + 16; +key_material(Cipher) when Cipher == rc2_cbc_56; + Cipher == rc4_56 -> + 7; +key_material(Cipher) when Cipher == rc2_cbc_40; + Cipher == rc4_40; + Cipher == des40_cbc -> + 5; +key_material(des_cbc) -> + 8; +key_material('3des_ede_cbc') -> + 24; +key_material(aes_128_cbc) -> + 16; +key_material(aes_256_cbc) -> + 32. + +expanded_key_material(null) -> + 0; +expanded_key_material(Cipher) when Cipher == idea_cbc; + Cipher == rc2_cbc_40; + Cipher == rc2_cbc_56; + Cipher == rc4_40; + Cipher == rc4_56; + Cipher == rc4_128 -> + 16; +expanded_key_material(Cipher) when Cipher == des_cbc; + Cipher == des40_cbc -> + 8; +expanded_key_material('3des_ede_cbc') -> + 24; +expanded_key_material(Cipher) when Cipher == aes_128_cbc; + Cipher == aes_256_cbc -> + unknown. + + +effective_key_bits(null) -> + 0; +effective_key_bits(Cipher) when Cipher == rc2_cbc_40; + Cipher == rc4_40; + Cipher == des40_cbc -> + 40; +effective_key_bits(Cipher) when Cipher == rc2_cbc_56; + Cipher == rc4_56; + Cipher == des_cbc -> + 56; +effective_key_bits(Cipher) when Cipher == idea_cbc; + Cipher == rc4_128; + Cipher == aes_128_cbc -> + 128; +effective_key_bits('3des_ede_cbc') -> + 168; +effective_key_bits(aes_256_cbc) -> + 256. + +iv_size(Cipher) when Cipher == null; + Cipher == rc4_40; + Cipher == rc4_56; + Cipher == rc4_128 -> + 0; +iv_size(Cipher) -> + block_size(Cipher). + +block_size(Cipher) when Cipher == idea_cbc; + Cipher == rc2_cbc_40; + Cipher == rc2_cbc_56; + Cipher == des40_cbc; + Cipher == des_cbc; + Cipher == '3des_ede_cbc' -> + 8; + +block_size(Cipher) when Cipher == aes_128_cbc; + Cipher == aes_256_cbc -> + 16. + +mac_algorithm(null) -> + ?NULL; +mac_algorithm(md5) -> + ?MD5; +mac_algorithm(sha) -> + ?SHA. + +hash_size(null) -> + 0; +hash_size(md5) -> + 16; +hash_size(sha) -> + 20. + +generic_block_cipher_from_bin(T, HashSize) -> + Sz1 = byte_size(T) - 1, + <<_:Sz1/binary, ?BYTE(PadLength)>> = T, + CompressedLength = byte_size(T) - PadLength - 1 - HashSize, + <<Content:CompressedLength/binary, Mac:HashSize/binary, + Padding:PadLength/binary, ?BYTE(PadLength)>> = T, + #generic_block_cipher{content=Content, mac=Mac, + padding=Padding, padding_length=PadLength}. + +generic_stream_cipher_from_bin(T, HashSz) -> + Sz = byte_size(T), + CompressedLength = Sz - HashSz, + <<Content:CompressedLength/binary, Mac:HashSz/binary>> = T, + #generic_stream_cipher{content=Content, + mac=Mac}. + +check_padding(_GBC) -> + ok. + +get_padding(Length, BlockSize) -> + get_padding_aux(BlockSize, Length rem BlockSize). + +get_padding_aux(_, 0) -> + {0, <<>>}; +get_padding_aux(BlockSize, PadLength) -> + N = BlockSize - PadLength, + {N, list_to_binary(lists:duplicate(N, N))}. + +next_iv(Bin, IV) -> + BinSz = byte_size(Bin), + IVSz = byte_size(IV), + FirstPart = BinSz - IVSz, + <<_:FirstPart/binary, NextIV:IVSz/binary>> = Bin, + NextIV. + |