aboutsummaryrefslogtreecommitdiffstats
path: root/lib/public_key
diff options
context:
space:
mode:
Diffstat (limited to 'lib/public_key')
-rw-r--r--lib/public_key/src/pubkey_pbe.erl105
-rw-r--r--lib/public_key/src/public_key.erl1
-rw-r--r--lib/public_key/test/pbe_SUITE.erl60
3 files changed, 97 insertions, 69 deletions
diff --git a/lib/public_key/src/pubkey_pbe.erl b/lib/public_key/src/pubkey_pbe.erl
index f471871d35..32be347039 100644
--- a/lib/public_key/src/pubkey_pbe.erl
+++ b/lib/public_key/src/pubkey_pbe.erl
@@ -27,35 +27,43 @@
-define(DEFAULT_SHA_MAC_KEYLEN, 20).
--define(OCTET_STR, 4).
--define(IV_LEN, 8).
+-define(ASN1_OCTET_STR_TAG, 4).
+-define(IV_LEN, 8).
%%====================================================================
%% Internal application API
%%====================================================================
-pbdkdf2(Password, Salt, Count, DerivedKeyLen, PrfLen, Prf)->
- NumBlocks = ceiling(DerivedKeyLen / PrfLen),
- NumLastBlockOctets = DerivedKeyLen - (NumBlocks - 1) * PrfLen ,
- blocks(NumBlocks, NumLastBlockOctets, 1, Password, Salt, Count, Prf, PrfLen, <<>>).
+pbdkdf2(Password, Salt, Count, DerivedKeyLen, Prf, PrfOutputLen)->
+ NumBlocks = ceiling(DerivedKeyLen / PrfOutputLen),
+ NumLastBlockOctets = DerivedKeyLen - (NumBlocks - 1) * PrfOutputLen ,
+ blocks(NumBlocks, NumLastBlockOctets, 1, Password, Salt, Count, Prf, PrfOutputLen, <<>>).
encode(Data, Password, "DES-CBC" = Cipher, KeyDevParams) ->
- {Key, IV} = password_to_key_and_iv(Password, derived_key_length(Cipher), KeyDevParams),
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
crypto:des_cbc_encrypt(Key, IV, Data);
encode(Data, Password, "DES-EDE3-CBC" = Cipher, KeyDevParams) ->
- {Key, IV} = password_to_key_and_iv(Password, derived_key_length(Cipher), KeyDevParams),
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
<<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
- crypto:des_ede3_cbc_encrypt(Key1, Key2, Key3, IV, Data).
+ crypto:des_ede3_cbc_encrypt(Key1, Key2, Key3, IV, Data);
+
+encode(Data, Password, "RC2-CBC" = Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:rc2_cbc_encrypt(Key, IV, Data).
decode(Data, Password,"DES-CBC"= Cipher, KeyDevParams) ->
- {Key, IV} = password_to_key_and_iv(Password, derived_key_length(Cipher), KeyDevParams),
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
crypto:des_cbc_decrypt(Key, IV, Data);
decode(Data, Password,"DES-EDE3-CBC" = Cipher, KeyDevParams) ->
- {Key, IV} = password_to_key_and_iv(Password, derived_key_length(Cipher), KeyDevParams),
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
<<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
- crypto:des_ede3_cbc_decrypt(Key1, Key2, Key3, IV, Data).
+ crypto:des_ede3_cbc_decrypt(Key1, Key2, Key3, IV, Data);
+
+decode(Data, Password,"RC2-CBC"= Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:rc2_cbc_decrypt(Key, IV, Data).
%%--------------------------------------------------------------------
-spec pbdkdf1(string(), iodata(), integer(), atom()) -> binary().
@@ -94,13 +102,20 @@ decrypt_parameters(#'EncryptedPrivateKeyInfo_encryptionAlgorithm'{
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-password_to_key_and_iv(Password, KeyLen, {salt, Salt}) ->
+password_to_key_and_iv(Password, Cipher, {salt, Salt}) ->
+ KeyLen = derived_key_length(Cipher, undefined),
<<Key:KeyLen/binary, _/binary>> =
pem_encrypt(<<>>, Password, Salt, ceiling(KeyLen div 16), <<>>, md5),
%% Old PEM encryption does not use standard encryption method
%% pbdkdf1 and uses then salt as IV
{Key, Salt}.
+password_to_key_and_iv(Password, _, #'PBES2-params'{} = Params) ->
+ {Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoOtputLen, IV} =
+ key_derivation_params(Params),
+ <<Key:KeyLen/binary, _/binary>> =
+ pbdkdf2(Password, Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoOtputLen),
+ {Key, IV}.
pem_encrypt(_, _, _, 0, Acc, _) ->
Acc;
pem_encrypt(Prev, Password, Salt, Count, Acc, Hash) ->
@@ -118,8 +133,12 @@ iv(#'PBES2-params_encryptionScheme'{algorithm = Algo,
(Algo == ?'des-EDE3-CBC') ->
%% This is an so called open ASN1-type that in this
%% case will be an octet-string of length 8
- <<?OCTET_STR, ?IV_LEN, IV:?IV_LEN/binary>> = ASNIV,
- IV.
+ <<?ASN1_OCTET_STR_TAG, ?IV_LEN, IV:?IV_LEN/binary>> = ASNIV,
+ IV;
+iv(#'PBES2-params_encryptionScheme'{algorithm = ?'rc2CBC',
+ parameters = ASN1IV}) ->
+ {ok, #'RC2-CBC-Parameter'{iv = IV}} = 'PKCS-FRAME':decode('RC2-CBC-Parameter', ASN1IV),
+ iolist_to_binary(IV).
blocks(1, N, Index, Password, Salt, Count, Prf, PrfLen, Acc) ->
<<XorSum:N/binary, _/binary>> = xor_sum(Password, Salt, Count, Index, Prf, PrfLen),
@@ -129,53 +148,55 @@ blocks(NumBlocks, N, Index, Password, Salt, Count, Prf, PrfLen, Acc) ->
blocks(NumBlocks -1, N, Index +1, Password, Salt, Count, Prf, PrfLen, <<Acc/binary, XorSum/binary>>).
xor_sum(Password, Salt, Count, Index, Prf, PrfLen) ->
- %%Result = Prf(Password, [Salt,<<Index:32/unsigned-big-integer>>], PrfLen),
- Result = Prf(Password, [Salt,<<Index:32/unsigned-big-integer>>]),
+ Result = Prf(Password, [Salt,<<Index:32/unsigned-big-integer>>], PrfLen),
do_xor_sum(Prf, PrfLen, Result, Password, Count-1, Result).
do_xor_sum(_, _, _, _, 0, Acc) ->
Acc;
do_xor_sum(Prf, PrfLen, Prev, Password, Count, Acc)->
- %%Result = Prf(Password, Prev, PrfLen),
- Result = Prf(Password, Prev),
+ Result = Prf(Password, Prev, PrfLen),
do_xor_sum(Prf, PrfLen, Result, Password, Count-1, crypto:exor(Acc, Result)).
decrypt_parameters(?'id-PBES2', DekParams) ->
{ok, Params} = 'PKCS-FRAME':decode('PBES2-params', DekParams),
{cipher(Params#'PBES2-params'.encryptionScheme), Params}.
-key_derivation_params(#'PBES2-params_keyDerivationFunc'{algorithm = ?'id-PBKDF2',
- parameters =
- #'PBKDF2-params'{salt = {specified, OctetSalt},
- iterationCount = Count,
- keyLength = Length,
- prf = Prf}}) ->
- PseudoRandomFunction = pseudo_random_function(Prf),
- KeyLen = pseudo_key_length(Length, Prf),
- {iolist_to_binary(OctetSalt), Count, KeyLen, PseudoRandomFunction}.
-
+key_derivation_params(#'PBES2-params'{keyDerivationFunc = KeyDerivationFunc,
+ encryptionScheme = EncScheme}) ->
+ #'PBES2-params_keyDerivationFunc'{algorithm = ?'id-PBKDF2',
+ parameters =
+ #'PBKDF2-params'{salt = {specified, OctetSalt},
+ iterationCount = Count,
+ keyLength = Length,
+ prf = Prf}} = KeyDerivationFunc,
+ #'PBES2-params_encryptionScheme'{algorithm = Algo} = EncScheme,
+ {PseudoRandomFunction, PseudoOtputLen} = pseudo_random_function(Prf),
+ KeyLen = derived_key_length(Algo, Length),
+ {iolist_to_binary(OctetSalt), Count, KeyLen, PseudoRandomFunction, PseudoOtputLen, iv(EncScheme)}.
+
+%% This function currently matches a tuple that ougth to be the value ?'id-hmacWithSHA1,
+%% but we need some kind of ASN1-fix for this.
pseudo_random_function(#'PBKDF2-params_prf'{algorithm = {_,_, _,'id-hmacWithSHA1'}}) ->
- %%fun crypto:sha_mac_n/3.
- fun crypto:sha_mac/2.
+ {fun crypto:sha_mac/3, pseudo_output_length(?'id-hmacWithSHA1')}.
-pseudo_key_length(asn1_NOVALUE, #'PBKDF2-params_prf'{algorithm = {_,_, _,'id-hmacWithSHA1'}}) ->
- ?DEFAULT_SHA_MAC_KEYLEN;
-pseudo_key_length(Len, _) when is_integer(Len) ->
- Len.
+pseudo_output_length(?'id-hmacWithSHA1') ->
+ ?DEFAULT_SHA_MAC_KEYLEN.
-derived_key_length("DES-CBC") ->
+derived_key_length(_, Len) when is_integer(Len) ->
+ Len;
+derived_key_length(Cipher,_) when (Cipher == ?'desCBC') or (Cipher == "DES-CBC") ->
8;
-%% derived_key_length("RC2-CBC") ->
-%% 5;
-derived_key_length("DES-EDE3-CBC") ->
+derived_key_length(Cipher,_) when (Cipher == ?'rc2CBC') or (Cipher == "RC2-CBC") ->
+ 16;
+derived_key_length(Cipher,_) when (Cipher == ?'des-EDE3-CBC') or (Cipher == "DES-EDE3-CBC") ->
24.
cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'desCBC'}) ->
"DES-CBC";
cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'des-EDE3-CBC'}) ->
- "DES-EDE3-CBC".
-%% cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'rc2CBC'}) ->
-%% "RC2-CBC".
+ "DES-EDE3-CBC";
+cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'rc2CBC'}) ->
+ "RC2-CBC".
ceiling(Float) ->
erlang:round(Float + 0.5).
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 68c7b7ad93..19465e7828 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -154,7 +154,6 @@ der_decode(Asn1Type, Der) when (Asn1Type == 'PrivateKeyInfo') or (Asn1Type == '
andalso is_binary(Der) ->
try
{ok, Decoded} = 'PKCS-FRAME':decode(Asn1Type, Der),
-
Decoded
catch
error:{badmatch, {error, _}} = Error ->
diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl
index 1d33976505..8dc9a01529 100644
--- a/lib/public_key/test/pbe_SUITE.erl
+++ b/lib/public_key/test/pbe_SUITE.erl
@@ -20,6 +20,7 @@
-module(pbe_SUITE).
-include_lib("test_server/include/test_server.hrl").
+-include_lib("public_key/include/public_key.hrl").
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -157,7 +158,7 @@ pbdkdf2(Config) when is_list(Config) ->
<<16#ea, 16#6c, 16#01, 16#4d, 16#c7, 16#2d, 16#6f, 16#8c,
16#cd, 16#1e, 16#d9, 16#2a, 16#ce, 16#1d, 16#41, 16#f0,
16#d8, 16#de, 16#89, 16#57>> =
- pubkey_pbe:pbdkdf2("password", "salt", 2, 20, 20, fun crypto:sha_mac/2),
+ pubkey_pbe:pbdkdf2("password", "salt", 2, 20, fun crypto:sha_mac/3, 20),
%% Input:
%% P = "password" (8 octets)
@@ -172,7 +173,7 @@ pbdkdf2(Config) when is_list(Config) ->
<<16#4b, 16#00, 16#79, 16#01, 16#b7, 16#65, 16#48, 16#9a,
16#be, 16#ad, 16#49, 16#d9, 16#26, 16#f7, 16#21, 16#d0,
- 16#65, 16#a4, 16#29, 16#c1>> = pubkey_pbe:pbdkdf2("password", "salt", 4096, 20, 20, fun crypto:sha_mac/2),
+ 16#65, 16#a4, 16#29, 16#c1>> = pubkey_pbe:pbdkdf2("password", "salt", 4096, 20, fun crypto:sha_mac/3, 20),
%% Input:
%% P = "password" (8 octets)
@@ -188,7 +189,7 @@ pbdkdf2(Config) when is_list(Config) ->
<<16#ee, 16#fe, 16#3d, 16#61, 16#cd, 16#4d, 16#a4, 16#e4,
16#e9, 16#94, 16#5b, 16#3d, 16#6b, 16#a2, 16#15, 16#8c,
- 16#26, 16#34, 16#e9, 16#84>> = pubkey_pbe:pbdkdf2("password", "salt", 16777216, 20, 20, fun crypto:sha_mac/2),
+ 16#26, 16#34, 16#e9, 16#84>> = pubkey_pbe:pbdkdf2("password", "salt", 16777216, 20, fun crypto:sha_mac/3, 20),
%% Input:
%% P = "passwordPASSWORDpassword" (24 octets)
@@ -207,7 +208,7 @@ pbdkdf2(Config) when is_list(Config) ->
16#8b, 16#29, 16#1a, 16#96, 16#4c, 16#f2, 16#f0, 16#70,
16#38>>
= pubkey_pbe:pbdkdf2("passwordPASSWORDpassword",
- "saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 25, 20, fun crypto:sha_mac/2),
+ "saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 25, fun crypto:sha_mac/3, 20),
%% Input:
%% P = "pass\0word" (9 octets)
@@ -222,30 +223,37 @@ pbdkdf2(Config) when is_list(Config) ->
<<16#56, 16#fa, 16#6a, 16#a7, 16#55, 16#48, 16#09, 16#9d,
16#cc, 16#37, 16#d7, 16#f0, 16#34, 16#25, 16#e0, 16#c3>>
= pubkey_pbe:pbdkdf2("pass\0word",
- "sa\0lt", 4096, 16, 20, fun crypto:sha_mac/2).
+ "sa\0lt", 4096, 16, fun crypto:sha_mac/3, 20).
-
-pbe_des_cbc(doc) ->
- ["Tests reading a password DES-CBC encrypted key file"];
-pbe_des_cbc(Config) when is_list(Config) ->
+encrypted_private_key_info(doc) ->
+ ["Tests reading a EncryptedPrivateKeyInfo file different ciphers"];
+encrypted_private_key_info(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
- {ok, Pem} = file:read_file(filename:join(Datadir, "des_cbc_enc_key.pem")),
+ {ok, PemDes} = file:read_file(filename:join(Datadir, "des_cbc_enc_key.pem")),
+ PemDesEntry = public_key:pem_decode(PemDes),
+ test_server:format("Pem entry: ~p" , [PemDesEntry]),
+ [{'PrivateKeyInfo', _, {"DES-CBC",_}} = PubEntry0] = PemDesEntry,
+ KeyInfo = public_key:pem_entry_decode(PubEntry0, "password"),
- PemE = public_key:pem_decode(Pem),
- test_server:format("PemE: ~p" , [PemE]),
- [{'PrivateKeyInfo', _, _} = PubEntry0] = PemE,
- Key = public_key:pem_entry_decode(PubEntry0, "password"),
- test_server:format("Key: ~p" , [Key]).
-
-pbe_des3_ede(doc) ->
- ["Tests reading a password DES-CBC encrypted key file"];
-pbe_des3_ede(Config) when is_list(Config) ->
- Datadir = ?config(data_dir, Config),
- {ok, Pem} = file:read_file(filename:join(Datadir, "des_ede3_cbc_enc_key.pem")),
+ {ok, Pem3Des} = file:read_file(filename:join(Datadir, "des_ede3_cbc_enc_key.pem")),
+
+ Pem3DesEntry = public_key:pem_decode(Pem3Des),
+ test_server:format("Pem entry: ~p" , [Pem3DesEntry]),
+ [{'PrivateKeyInfo', _, {"DES-EDE3-CBC",_}} = PubEntry1] = Pem3DesEntry,
+ KeyInfo = public_key:pem_entry_decode(PubEntry1, "password"),
+
+ {ok, PemRc2} = file:read_file(filename:join(Datadir, "rc2_cbc_enc_key.pem")),
+
+ PemRc2Entry = public_key:pem_decode(PemRc2),
+ test_server:format("Pem entry: ~p" , [PemRc2Entry]),
+ [{'PrivateKeyInfo', _, {"RC2-CBC",_}} = PubEntry2] = PemRc2Entry,
+ KeyInfo = public_key:pem_entry_decode(PubEntry2, "password"),
+
+ check_key_info(KeyInfo).
+
- PemE = public_key:pem_decode(Pem),
- test_server:format("PemE: ~p" , [PemE]),
- [{'PrivateKeyInfo', _, _} = PubEntry0] = PemE,
- Key = public_key:pem_entry_decode(PubEntry0, "password"),
- test_server:format("Key: ~p" , [Key]).
+check_key_info(#'PrivateKeyInfo'{privateKeyAlgorithm =
+ #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?rsaEncryption},
+ privateKey = Key}) ->
+ #'RSAPrivateKey'{} = public_key:der_decode('RSAPrivateKey', iolist_to_binary(Key)).