diff options
Diffstat (limited to 'lib/ssh/src/ssh_rsa.erl')
-rwxr-xr-x | lib/ssh/src/ssh_rsa.erl | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/lib/ssh/src/ssh_rsa.erl b/lib/ssh/src/ssh_rsa.erl new file mode 100755 index 0000000000..7c2bf9a2bf --- /dev/null +++ b/lib/ssh/src/ssh_rsa.erl @@ -0,0 +1,299 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-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% +%% + +%% + +%%% Description: rsa public-key sign and verify + +-module(ssh_rsa). + +-export([verify/3, sign/2]). +-export([alg_name/0]). + +-include("ssh.hrl"). +-include("PKCS-1.hrl"). + + +-define(MGF(Seed,Len), mgf1((Seed),(Len))). +-define(HASH(X), crypto:sha((X))). +-define(HLen, 20). + +%% start() -> +%% crypto:start(). + +%% sign_file(File) -> +%% start(), +%% {ok,Bin} = file:read_file(File), +%% {ok,Key} = ssh_file:private_host_rsa_key(user), +%% sign(Key, Bin). + +%% verify_file(File, Sig) -> +%% start(), +%% {ok,Bin} = file:read_file(File), +%% {ok,Key} = ssh_file:public_host_rsa_key(user), +%% verify(Key, Bin, Sig). + +sign(Private,Mb) -> + rsassa_pkcs1_v1_5_sign(Private,Mb). + +verify(Public,Mb,Sb) -> + rsassa_pkcs1_v1_5_verify(Public,Mb,Sb). + + + +%% Integer to octet string +i2osp(X, XLen) -> + ssh_bits:i2bin(X, XLen). + +%% Octet string to Integer +os2ip(X) -> + ssh_bits:bin2i(X). + +%% decrypt1, M = message representative +%% rsaep(#ssh_key { public={N,E}}, M) -> +%% ?ssh_assert(M >= 0 andalso M =< N-1, out_of_range), +%% ssh_math:ipow(M, E, N). + +%% encrypt1, C = cipher representative +%% rsadp(#ssh_key { public={N,_}, private={_,D}}, C) -> +%% ?ssh_assert(C >= 0 andalso C =< N-1, out_of_range), +%% ssh_math:ipow(C, D, N). + +%% sign1, M = message representative +rsasp1(#ssh_key { public={N,_}, private={_,D}}, M) -> + ?ssh_assert((M >= 0 andalso M =< N-1), out_of_range), + ssh_math:ipow(M, D, N). + +%% verify1, S =signature representative +rsavp1(#ssh_key { public={N,E}}, S) -> + ?ssh_assert(S >= 0 andalso S =< N-1, out_of_range), + ssh_math:ipow(S, E, N). + + +%% M messaage +%% rsaes_oaep_encrypt(Public, M) -> +%% rsaes_oaep_encrypt(Public, M, <<>>). + +%% rsaes_oaep_encrypt(Public=#ssh_key { public={N,_E}}, M, L) -> +%% ?ssh_assert(size(L) =< 16#ffffffffffffffff, label_to_long), +%% K = (ssh_bits:isize(N)+7) div 8, +%% MLen = size(M), +%% %% LLen = size(L), +%% ?ssh_assert(MLen =< K - 2*?HLen - 2, message_to_long), +%% LHash = ?HASH(L), +%% PS = ssh_bits:fill_bits(K - MLen - 2*?HLen - 2, 0), +%% DB = <<LHash/binary, PS/binary, 16#01, M/binary>>, +%% Seed = ssh_bits:random(?HLen), +%% DbMask = ?MGF(Seed, K - ?HLen - 1), +%% MaskedDB = ssh_bits:xor_bits(DB, DbMask), +%% SeedMask = ?MGF(MaskedDB, ?HLen), +%% MaskedSeed = ssh_bits:xor_bits(Seed, SeedMask), +%% EM = <<16#00, MaskedSeed/binary, MaskedDB/binary>>, +%% Mc = os2ip(EM), +%% C = rsaep(Public, Mc), +%% i2osp(C, K). + +%% rsaes_oaep_decrypt(Key, C) -> +%% rsaes_oaep_decrypt(Key, C, <<>>). + +%% rsaes_oaep_decrypt(Private=#ssh_key { public={N,_},private={_,_}},Cb,L) -> +%% ?ssh_assert(size(L) =< 16#ffffffffffffffff, label_to_long), +%% K = (ssh_bits:isize(N)+7) div 8, +%% ?ssh_assert(K == 2*?HLen + 2, decryption_error), +%% C = os2ip(Cb), +%% M = rsadp(Private, C), +%% EM = i2osp(M, K), +%% LHash = ?HASH(L), +%% MLen = K - ?HLen -1, +%% case EM of +%% <<16#00, MaskedSeed:?HLen/binary, MaskedDB:MLen>> -> +%% SeedMask = ?MGF(MaskedDB, ?HLen), +%% Seed = ssh_bits:xor_bits(MaskedSeed, SeedMask), +%% DbMask = ?MGF(Seed, K - ?HLen - 1), +%% DB = ssh_bits:xor_bits(MaskedDB, DbMask), +%% PSLen = K - MLen - 2*?HLen - 2, +%% case DB of +%% <<LHash:?HLen, _PS:PSLen/binary, 16#01, M/binary>> -> +%% M; +%% _ -> +%% exit(decryption_error) +%% end; +%% _ -> +%% exit(decryption_error) +%% end. + + +%% rsaes_pkcs1_v1_5_encrypt(Public=#ssh_key { public={N,_}}, M) -> +%% K = (ssh_bits:isize(N)+7) div 8, +%% MLen = size(M), +%% ?ssh_assert(MLen =< K - 11, message_to_long), +%% PS = ssh_bits:random(K - MLen - 3), +%% EM = <<16#00,16#02,PS/binary,16#00,M/binary>>, +%% Mc = os2ip(EM), +%% C = rsaep(Public, Mc), +%% i2osp(C, K). + + +%% rsaes_pkcs1_v1_5_decrypt(Private=#ssh_key { public={N,_},private={_,_}}, +%% Cb) -> +%% K = (ssh_bits:isize(N)+7) div 8, +%% CLen = size(Cb), +%% ?ssh_assert(CLen == K andalso K >= 11, decryption_error), +%% C = os2ip(Cb), +%% M = rsadp(Private, C), +%% EM = i2osp(M, K), +%% PSLen = K - CLen - 3, +%% case EM of +%% <<16#00, 16#02, _PS:PSLen/binary, 16#00, M>> -> +%% M; +%% _ -> +%% exit(decryption_error) +%% end. + +%% rsassa_pss_sign(Private=#ssh_key { public={N,_},private={_,_}},Mb) -> +%% ModBits = ssh_bits:isize(N), +%% K = (ModBits+7) div 8, +%% EM = emsa_pss_encode(Mb, ModBits - 1), +%% M = os2ip(EM), +%% S = rsasp1(Private, M), +%% i2osp(S, K). + +%% rsassa_pss_verify(Public=#ssh_key { public={N,_E}},Mb,Sb) -> +%% ModBits = ssh_bits:isize(N), +%% K = (ModBits+7) div 8, +%% ?ssh_assert(size(Sb) == K, invalid_signature), +%% S = os2ip(Sb), +%% M = rsavp1(Public,S), +%% EMLen = (ModBits-1+7) div 8, +%% EM = i2osp(M, EMLen), +%% emsa_pss_verify(Mb, EM, ModBits-1). + + +rsassa_pkcs1_v1_5_sign(Private=#ssh_key { public={N,_},private={_,_D}},Mb) -> + K = (ssh_bits:isize(N)+7) div 8, + EM = emsa_pkcs1_v1_5_encode(Mb, K), + M = os2ip(EM), + S = rsasp1(Private, M), + i2osp(S, K). + +rsassa_pkcs1_v1_5_verify(Public=#ssh_key { public={N,_E}}, Mb, Sb) -> + K = (ssh_bits:isize(N)+7) div 8, + ?ssh_assert(size(Sb) == K, invalid_signature), + S = os2ip(Sb), + M = rsavp1(Public, S), + EM = i2osp(M, K), + %?dbg(true, "verify K=~p S=~w ~n#M=~w~n#EM=~w~n", [K, S, M, EM]), + case emsa_pkcs1_v1_5_encode(Mb, K) of + EM -> ok; + _S -> + io:format("S: ~p~n", [_S]), + {error, invalid_signature} % exit(invalid_signature) + end. + + +emsa_pkcs1_v1_5_encode(M, EMLen) -> + H = ?HASH(M), + %% Must use speical xxNull types here! + Alg = #'AlgorithmNull' { algorithm = ?'id-sha1', + parameters = <<>> }, + {ok,TCode} = 'PKCS-1':encode('DigestInfoNull', + #'DigestInfoNull'{ digestAlgorithm = Alg, + digest = H }), + T = list_to_binary(TCode), + TLen = size(T), + ?ssh_assert(EMLen >= TLen + 11, message_to_short), + PS = ssh_bits:fill_bits(EMLen - TLen - 3, 16#ff), + <<16#00, 16#01, PS/binary, 16#00, T/binary>>. + + +%% emsa_pss_encode(M, EMBits) -> +%% emsa_pss_encode(M, EMBits, 0). + +%% emsa_pss_encode(M, EMBits, SLen) -> +%% ?ssh_assert(size(M) =< 16#ffffffffffffffff, message_to_long), +%% EMLen = (EMBits + 7) div 8, +%% MHash = ?HASH(M), +%% ?ssh_assert(EMLen >= ?HLen + SLen + 2, encoding_error), +%% Salt = ssh_bits:random(SLen), +%% M1 = [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, +%% MHash, Salt], +%% H = ?HASH(M1), +%% PS = ssh_bits:fill_bits(EMLen-SLen-?HLen-2, 0), +%% DB = <<PS/binary, 16#01, Salt/binary>>, +%% DbMask = ?MGF(H, EMLen - ?HLen -1), +%% MaskedDB = ssh_bits:xor_bits(DB, DbMask), +%% ZLen = 8*EMLen - EMBits, +%% NZLen = (8 - (ZLen rem 8)) rem 8, +%% <<_:ZLen, NZ:NZLen, MaskedDB1/binary>> = MaskedDB, +%% MaskedDB2 = <<0:ZLen, NZ:NZLen, MaskedDB1/binary>>, +%% <<MaskedDB2/binary, H/binary, 16#BC>>. + + +%% emsa_pss_verify(M, EM, EMBits) -> +%% emsa_pss_verify(M, EM, EMBits, 0). + +%% emsa_pss_verify(M, EM, EMBits, SLen) -> +%% ?ssh_assert(size(M) =< 16#ffffffffffffffff, message_to_long), +%% EMLen = (EMBits + 7) div 8, +%% MHash = ?HASH(M), +%% ?ssh_assert(EMLen >= ?HLen + SLen + 2, inconsistent), +%% MaskLen = (EMLen - ?HLen - 1)-1, +%% ZLen = 8*EMLen - EMBits, +%% NZLen = (8 - (ZLen rem 8)) rem 8, +%% case EM of +%% <<0:ZLen,Nz:NZLen,MaskedDB1:MaskLen/binary, H:?HLen/binary, 16#BC>> -> +%% MaskedDB = <<0:ZLen,Nz:NZLen,MaskedDB1/binary>>, +%% DbMask = ?MGF(H, EMLen - ?HLen - 1), +%% DB = ssh_bits:xor_bits(MaskedDB, DbMask), +%% PSLen1 = (EMLen - SLen - ?HLen - 2) - 1, +%% PS = ssh_bits:fill_bits(PSLen1, 0), +%% case DB of +%% <<_:ZLen,0:NZLen,PS:PSLen1/binary,16#01,Salt:SLen/binary>> -> +%% M1 = [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, +%% MHash, Salt], +%% case ?HASH(M1) of +%% H -> ok; +%% _ -> exit(inconsistent) +%% end; +%% _ -> +%% exit(inconsistent) +%% end; +%% _ -> +%% exit(inconsistent) +%% end. + + + +%% Mask generating function MGF1 +%% mgf1(MGFSeed, MaskLen) -> +%% T = mgf1_loop(0, ((MaskLen + ?HLen -1) div ?HLen) - 1, MGFSeed, ""), +%% <<R:MaskLen/binary, _/binary>> = T, +%% R. + +%% mgf1_loop(Counter, N, _, T) when Counter > N -> +%% list_to_binary(T); +%% mgf1_loop(Counter, N, MGFSeed, T) -> +%% C = i2osp(Counter, 4), +%% mgf1_loop(Counter+1, N, MGFSeed, [T, ?HASH([MGFSeed, C])]). + + + + +alg_name() -> + "ssh-rsa". |