From cb1305212e71855890bbfb0a509a007543529d24 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 3 May 2013 10:20:37 +0200 Subject: ssl & crypto: Generalize the remaining crypto API --- lib/crypto/c_src/crypto.c | 6 ++- lib/crypto/doc/src/crypto.xml | 106 ++++++++++++++++++++------------------ lib/crypto/doc/src/crypto_app.xml | 36 ++++--------- lib/crypto/src/crypto.erl | 42 ++++++++------- lib/crypto/test/crypto_SUITE.erl | 10 ++-- lib/ssl/src/ssl_cipher.erl | 4 +- lib/ssl/src/ssl_connection.erl | 2 +- lib/stdlib/src/otp_internal.erl | 2 +- 8 files changed, 103 insertions(+), 105 deletions(-) (limited to 'lib') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index c5d181ea25..0129526303 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -496,6 +496,7 @@ static ERL_NIF_TERM atom_sha256; static ERL_NIF_TERM atom_sha384; static ERL_NIF_TERM atom_sha512; static ERL_NIF_TERM atom_md5; +static ERL_NIF_TERM atom_md4; static ERL_NIF_TERM atom_ripemd160; static ERL_NIF_TERM atom_error; static ERL_NIF_TERM atom_rsa_pkcs1_padding; @@ -590,6 +591,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info) atom_sha256 = enif_make_atom(env,"sha256"); atom_sha384 = enif_make_atom(env,"sha384"); atom_sha512 = enif_make_atom(env,"sha512"); + atom_md4 = enif_make_atom(env,"md4"); atom_md5 = enif_make_atom(env,"md5"); atom_ripemd160 = enif_make_atom(env,"ripemd160"); atom_error = enif_make_atom(env,"error"); @@ -708,12 +710,12 @@ static void unload(ErlNifEnv* env, void* priv_data) } static int algos_cnt; -static ERL_NIF_TERM algos[8]; /* increase when extending the list */ +static ERL_NIF_TERM algos[9]; /* increase when extending the list */ static void init_algorithms_types(void) { algos_cnt = 0; - + algos[algos_cnt++] = atom_md4; algos[algos_cnt++] = atom_md5; algos[algos_cnt++] = atom_sha; algos[algos_cnt++] = atom_ripemd160; diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 0fb53346ca..df765ade87 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -30,23 +30,24 @@

-

Hash functions - The MD4 Message Digest Algorithm (RFC 1320), +

Hash functions - + Secure Hash Standard, The MD5 Message Digest Algorithm (RFC 1321) and - Secure Hash Standard + The MD4 Message Digest Algorithm (RFC 1320)

Hmac functions - Keyed-Hashing for Message Authentication (RFC 2104)

-

Block ciphers - DES and AES and - and Block Cipher Modes - ECB, CBC, CFB, OFB and CTR

+

Block ciphers - DES and AES in + Block Cipher Modes - ECB, CBC, CFB, OFB and CTR

RSA encryption RFC 1321

-

Digital signatures Digital Signature Standard (DSS) and Elliptic Curve Digital +

Digital signatures Digital Signature Standard (DSS) and Elliptic Curve Digital Signature Algorithm (ECDSA)

@@ -57,13 +58,7 @@
DATA TYPES - -

byte() = 0 ... 255

- -

ioelem() = byte() | binary() | iolist()

- -

iolist() = [ioelem()]

- +

key_value() = integer() | binary()

rsa_public() = [key_value()] = [E, N]

@@ -74,7 +69,7 @@ the private exponent.The longer key format contains redundant information that will make the calculation faster. P1,P2 are first and second prime factors. E1,E2 are first and second exponents. C - is the CRT coefficient. Terminology is taken from RFC 3447.

+ is the CRT coefficient. Terminology is taken from RFC 3447.

dss_public() = [key_value()] = [P, Q, G, Y]

Where P, Q and G are the dss parameters and Y is the public key.

@@ -137,25 +132,28 @@

block_key() = aes_key() | blowfish_key() | des_key()| des3_key()

-

aes_key() = binary() Key length is 128, 192 or 256 bits

+

aes_key() = iodata() Key length is 128, 192 or 256 bits

-

rc4_key() = binary() Variable key length from 8 bits up to 2048 bits (usually between 40 and 256)

+

rc4_key() = iodata() Variable key length from 8 bits up to 2048 bits (usually between 40 and 256)

-

blowfish_key() = binary() Variable key length from 32 bits up to 448 bits

+

blowfish_key() = iodata() Variable key length from 32 bits up to 448 bits

-

des_key() = binary() Key length is 64 bits (in CBC mod only 8 bits are used)

+

des_key() = iodata() Key length is 64 bits (in CBC mode only 8 bits are used)

-

des3_key() = [binary(), binary(), binary()] Each key part is 64 bits (in CBC mod only 8 bits are used)

+

des3_key() = [binary(), binary(), binary()] Each key part is 64 bits (in CBC mode only 8 bits are used)

+ +

message_digest_algorithms() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 md4 is aslo supported for hash_init/1 and hash/2. + Note that both md4 and md5 are recommended only for compatibility with existing applications. +

- algorithms() -> [atom()] + algorithms() -> [message_digest_algorithms() | md4 | ec] Provide a list of available crypto algorithms. -

Provides the available crypto algorithms in terms of a list - of atoms. This is interesting as older versions of the openssl - crypto library may not support all algorithms used in the crypto API.

+

Can be used to determine if the crypto library has support for elliptic curve (ec) and + which message digest algorithms that are supported.

@@ -164,7 +162,7 @@ Encrypt PlainTextaccording to Type block cipher Key = block_key() - PlainText = iodata() | binary() + PlainText = iodata() IVec = CipherText = binary() @@ -179,7 +177,7 @@ Decrypt CipherTextaccording to Type block cipher Key = block_key() - PlainText = iodata() | binary() + PlainText = iodata() IVec = CipherText = binary() @@ -201,6 +199,7 @@

Computes the shared secret from the private key and the other party's public key. + See also public_key:compute_key/2

@@ -209,7 +208,7 @@ exor(Data1, Data2) -> Result XOR data - Data1, Data2 = iolist() | binary() + Data1, Data2 = iodata() Result = binary() @@ -229,6 +228,7 @@

Generates public keys of type Type. + See also public_key:generate_key/1

@@ -237,7 +237,7 @@ hash(Type, Data) -> Digest - Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 + Type = md4 | message_digest_algorithms() Data = iodata() Digest = binary() @@ -252,7 +252,7 @@ hash_init(Type) -> Context - Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 + Type = md4 | message_digest_algorithms()

Initializes the context for streaming hash operations. Type determines @@ -296,7 +296,7 @@ hmac(Type, Key, Data, MacLength) -> Mac - Type = md5 | sha | sha224 | sha256 | sha384 | sha512 + Type = message_digest_algorithms() Key = iodata() Data = iodata() MacLength = integer() @@ -313,8 +313,8 @@ hmac_init(Type, Key) -> Context - Type = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 - Key = iolist() | binary() + Type = message_digest_algorithms() + Key = iodata() Context = binary() @@ -329,13 +329,17 @@ Context = NewContext = binary() - Data = iolist() | binary() + Data = iodata()

Updates the HMAC represented by Context using the given Data. Context must have been generated using an HMAC init function (such as hmac_init). Data can be any length. NewContext - must be passed into the next call to hmac_update.

+ must be passed into the next call to hmac_update + or to one of the functions hmac_final and + hmac_final_n +

+
@@ -391,10 +395,10 @@ - mod_exp_prime(N, P, M) -> Result + mod_pow(N, P, M) -> Result Computes the function: N^P mod M - N, P, M = binary() + N, P, M = binary() | integer() Result = binary() | error @@ -433,6 +437,7 @@ message. The Padding is the padding mode that was used to encrypt the data, see public_encrypt/3. + See also public_key:decrypt_private/[2,3]

@@ -455,6 +460,7 @@ The size of the Msg must be less than byte_size(N)-11 if rsa_pkcs1_padding is used, and byte_size(N) if rsa_no_padding is used. + See also public_key:encrypt_private/[2,3]

@@ -475,6 +481,7 @@ message. The Padding is the padding mode that was used to encrypt the data, see private_encrypt/3. + See also public_key:decrypt_public/[2,3]

@@ -501,6 +508,7 @@ rsa_pkcs1_padding is used, byte_size(N)-41 if rsa_pkcs1_oaep_padding is used and byte_size(N) if rsa_no_padding is used. + See also public_key:encrypt_public/[2,3]

@@ -545,6 +553,7 @@

Creates a digital signature.

+ See also public_key:sign/3
@@ -613,36 +622,32 @@ - stream_encrypt(Type, State, PlainText) -> { NewState, CipherText} + stream_encrypt(State, PlainText) -> { NewState, CipherText} - Type = stream_cipher() - Text = iolist() | binary() + Text = iodata() CipherText = binary() -

Encrypts PlainText according to the stream cipher Type. - Text can be any number of bytes. State is initialized using - stream_init on - the next invocation of this function the returned State shall be - given as input and so on until the end of the stream is reached.

+

Encrypts PlainText according to the stream cipher Type specified in stream_init/3. + Text can be any number of bytes. The initial State is created using + stream_init. + NewState must be passed into the next call to stream_encrypt.

- stream_decrypt(Type, State, CipherText) -> { NewState, PlainText } + stream_decrypt(State, CipherText) -> { NewState, PlainText } - Type = stream_cipher() - CipherText = iodata() | binary() + CipherText = iodata() PlainText = binary() -

Decrypts CipherText according to the stream cipher Type. - PlainText can be any number of bytes. State is initialized using - stream_init on - the next invocation of this function the returned State shall be - given as input and so on until the end of the stream is reached.

+

Decrypts CipherText according to the stream cipher Type specified in stream_init/3. + PlainText can be any number of bytes. The initial State is created using + stream_init. + NewState must be passed into the next call to stream_encrypt.

@@ -660,6 +665,7 @@

Verifies a digital signature

+ See also public_key:verify/3
diff --git a/lib/crypto/doc/src/crypto_app.xml b/lib/crypto/doc/src/crypto_app.xml index 20f4ed5c45..6d26076c04 100644 --- a/lib/crypto/doc/src/crypto_app.xml +++ b/lib/crypto/doc/src/crypto_app.xml @@ -29,37 +29,23 @@ crypto The Crypto Application -

The purpose of the Crypto application is to provide erlang - acess to crypto graphic functions in openssl. +

The purpose of the Crypto application is to provide an Erlang API + to cryptographic functions, see crypto(3). + Note that the API is on a fairly low level and there are some + corresponding API functions available in public_key(3), + on a higher abstraction level, that uses the crypto application in its implementation.

- Configuration -

The following environment configuration parameters are defined - for the Crypto application. Refer to application(3) for more - information about configuration parameters. -

- - ]]> - -

Causes debug information to be written to standard - error or standard output. Default is false. -

-
-
-
+ DEPENDENCIES -
- OpenSSL libraries -

The current implementation of the Erlang Crypto application is - based on the OpenSSL package version 0.9.8 or higher. - There are source and binary releases on the web. -

+

The current crypto implementation uses nifs to interface OpenSSLs crypto library + and requires OpenSSL package version 0.9.8 or higher.

Source releases of OpenSSL can be downloaded from the OpenSSL project home page, - or mirror sites listed there. -

-
+ or mirror sites listed there. +

+
SEE ALSO diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index f3fd119cdd..f4e157198c 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -26,11 +26,11 @@ -export([sign/4, verify/5]). -export([generate_key/2, generate_key/3, compute_key/4]). -export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]). --export([exor/2, strong_rand_bytes/1, mod_exp_prime/3]). +-export([exor/2, strong_rand_bytes/1, mod_pow/3]). -export([rand_bytes/1, rand_bytes/3, rand_uniform/2]). -export([block_encrypt/3, block_decrypt/3, block_encrypt/4, block_decrypt/4]). -export([next_iv/2, next_iv/3]). --export([stream_init/2, stream_init/3, stream_encrypt/3, stream_decrypt/3]). +-export([stream_init/2, stream_init/3, stream_encrypt/2, stream_decrypt/2]). -export([public_encrypt/4, private_decrypt/4]). -export([private_encrypt/4, public_decrypt/4]). @@ -193,7 +193,7 @@ rand_bytes, strong_rand_bytes, rand_uniform, - mod_exp_prime, + mod_pow, exor, %% deprecated mod_exp,strong_rand_mpint,erlint, mpint, @@ -685,7 +685,7 @@ sha512_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. %% Ecrypt/decrypt %%% -spec block_encrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | - blowfish_cfb64 | aes_cbc128 | aes_cfb128 | rc2_cbc, + blowfish_cfb64 | aes_cbc128 | aes_cfb128 | aes_cbc256 | rc2_cbc, Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). block_encrypt(des_cbc, Key, Ivec, Data) -> @@ -714,7 +714,7 @@ block_encrypt(rc2_cbc, Key, Ivec, Data) -> rc2_cbc_encrypt(Key, Ivec, Data). -spec block_decrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | - blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cfb128 | rc2_cbc, + blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cbc256 | aes_cfb128 | rc2_cbc, Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). block_decrypt(des_cbc, Key, Ivec, Data) -> @@ -769,17 +769,21 @@ next_iv(des_cbf, Ivec, Data) -> des_cfb_ivec(Ivec, Data). stream_init(aes_ctr, Key, Ivec) -> - aes_ctr_stream_init(Key, Ivec). + {aes_ctr, aes_ctr_stream_init(Key, Ivec)}. stream_init(rc4, Key) -> - rc4_set_key(Key). -stream_encrypt(aes_ctr, State, Data) -> - aes_ctr_stream_encrypt(State, Data); -stream_encrypt(rc4, State, Data) -> - rc4_encrypt_with_state(State, Data). -stream_decrypt(aes_ctr, State, Data) -> - aes_ctr_stream_decrypt(State, Data); -stream_decrypt(rc4, State, Data) -> - rc4_encrypt_with_state (State, Data). + {rc4, rc4_set_key(Key)}. +stream_encrypt({aes_ctr, State}, Data) -> + {State, Cipher} = aes_ctr_stream_encrypt(State, Data), + {{aes_ctr, State}, Cipher}; +stream_encrypt({rc4, State0}, Data) -> + {State, Cipher} = rc4_encrypt_with_state(State0, Data), + {{rc4, State}, Cipher}. +stream_decrypt({aes_ctr, State0}, Data) -> + {State, Text} = aes_ctr_stream_decrypt(State0, Data), + {{aes_ctr, State}, Text}; +stream_decrypt({rc4, State0}, Data) -> + {State, Text} = rc4_encrypt_with_state (State0, Data), + {{rc4, State}, Text}. %% %% CRYPTO FUNCTIONS @@ -1018,9 +1022,9 @@ mod_exp(Base, Exponent, Modulo) mod_exp(Base, Exponent, Modulo) -> mod_exp_nif(mpint_to_bin(Base),mpint_to_bin(Exponent),mpint_to_bin(Modulo), 4). --spec mod_exp_prime(binary(), binary(), binary()) -> binary() | error. -mod_exp_prime(Base, Exponent, Prime) -> - case mod_exp_nif(Base, Exponent, Prime, 0) of +-spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error. +mod_pow(Base, Exponent, Prime) -> + case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of <<0>> -> error; R -> R end. @@ -1500,7 +1504,7 @@ term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub. %% user_srp_gen_key(Private, Generator, Prime) -> - case mod_exp_prime(Generator, Private, Prime) of + case mod_pow(Generator, Private, Prime) of error -> error; Public -> diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index cff257bb8c..eddb6b83f9 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1979,8 +1979,8 @@ srp3(Config) when is_list(Config) -> "9176A9192615DC0277AE7C12F1F6A7F6563FCA11675D809AF578BDE5" "2B51E05D440B63099A017A0B45044801"), UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), - Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime), - ClientPublic = crypto:mod_exp_prime(Generator, ClientPrivate, Prime), + Verifier = crypto:mod_pow(Generator, UserPassHash, Prime), + ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime), {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate), {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate), @@ -2030,8 +2030,8 @@ srp6(Config) when is_list(Config) -> "72E992AAD89095A84B6A5FADA152369AB1E350A03693BEF044DF3EDF" "0C34741F4696C30E9F675D09F58ACBEB"), UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), - Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime), - ClientPublic = crypto:mod_exp_prime(Generator, ClientPrivate, Prime), + Verifier = crypto:mod_pow(Generator, UserPassHash, Prime), + ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime), {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate), {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate), @@ -2081,7 +2081,7 @@ srp6a(Config) when is_list(Config) -> "3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D" "C346D7E474B29EDE8A469FFECA686E5A"), UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), - Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime), + Verifier = crypto:mod_pow(Generator, UserPassHash, Prime), {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate), {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate), diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 5ce1350f09..accea63344 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -77,7 +77,7 @@ cipher(?RC4, CipherState, Mac, Fragment, _Version) -> S -> S end, GenStreamCipherList = [Fragment, Mac], - {State1, T} = crypto:stream_encrypt(rc4, State0, GenStreamCipherList), + {State1, T} = crypto:stream_encrypt(State0, GenStreamCipherList), {T, CipherState#cipher_state{state = State1}}; cipher(?DES, CipherState, Mac, Fragment, Version) -> block_cipher(fun(Key, IV, T) -> @@ -130,7 +130,7 @@ decipher(?RC4, HashSz, CipherState, Fragment, _) -> undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key); S -> S end, - try crypto:stream_decrypt(rc4, State0, Fragment) of + try crypto:stream_decrypt(State0, Fragment) of {State, Text} -> GSC = generic_stream_cipher_from_bin(Text, HashSz), #generic_stream_cipher{content = Content, mac = Mac} = GSC, diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index eb2fc5467d..54eed03d3c 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -2188,7 +2188,7 @@ handle_srp_identity(Username, {Fun, UserState}) -> {ok, {SRPParams, Salt, DerivedKey}} when is_atom(SRPParams), is_binary(Salt), is_binary(DerivedKey) -> {Generator, Prime} = ssl_srp_primes:get_srp_params(SRPParams), - Verifier = crypto:mod_exp_prime(Generator, DerivedKey, Prime), + Verifier = crypto:mod_pow(Generator, DerivedKey, Prime), #srp_user{generator = Generator, prime = Prime, salt = Salt, verifier = Verifier}; #alert{} = Alert -> diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl index 38edf3781e..f2849e50ec 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -122,7 +122,7 @@ obsolete_1(crypto, dss_verify, 4) -> {deprecated, {crypto, verify, 4}}; obsolete_1(crypto, mod_exp, 3) -> - {deprecated, {crypto, mod_exp_prime, 3}}; + {deprecated, {crypto, mod_pow, 3}}; obsolete_1(crypto, dh_compute_key, 3) -> {deprecated, {crypto, compute_key, 4}}; -- cgit v1.2.3