1
%% ``The contents of this file are subject to the Erlang Public License,
2
%% Version 1.1, (the "License"); you may not use this file except in
3
%% compliance with the License. You should have received a copy of the
4
%% Erlang Public License along with this software. If not, it can be
5
%% retrieved via the world wide web at http://www.erlang.org/.
7
%% Software distributed under the License is distributed on an "AS IS"
8
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
%% the License for the specific language governing rights and limitations
12
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
%% AB. All Rights Reserved.''
19
%%% Description: rsa public-key sign and verify
23
-export([verify/3, sign/2]).
24
-export([alg_name/0]).
27
-include("PKCS-1.hrl").
30
-define(MGF(Seed,Len), mgf1((Seed),(Len))).
31
-define(HASH(X), crypto:sha((X))).
39
%% {ok,Bin} = file:read_file(File),
40
%% {ok,Key} = ssh_file:private_host_rsa_key(user),
43
%% verify_file(File, Sig) ->
45
%% {ok,Bin} = file:read_file(File),
46
%% {ok,Key} = ssh_file:public_host_rsa_key(user),
47
%% verify(Key, Bin, Sig).
50
rsassa_pkcs1_v1_5_sign(Private,Mb).
52
verify(Public,Mb,Sb) ->
53
rsassa_pkcs1_v1_5_verify(Public,Mb,Sb).
57
%% Integer to octet string
59
ssh_bits:i2bin(X, XLen).
61
%% Octet string to Integer
65
%% decrypt1, M = message representative
66
%% rsaep(#ssh_key { public={N,E}}, M) ->
67
%% ?ssh_assert(M >= 0 andalso M =< N-1, out_of_range),
68
%% ssh_math:ipow(M, E, N).
70
%% encrypt1, C = cipher representative
71
%% rsadp(#ssh_key { public={N,_}, private={_,D}}, C) ->
72
%% ?ssh_assert(C >= 0 andalso C =< N-1, out_of_range),
73
%% ssh_math:ipow(C, D, N).
75
%% sign1, M = message representative
76
rsasp1(#ssh_key { public={N,_}, private={_,D}}, M) ->
77
?ssh_assert((M >= 0 andalso M =< N-1), out_of_range),
78
ssh_math:ipow(M, D, N).
80
%% verify1, S =signature representative
81
rsavp1(#ssh_key { public={N,E}}, S) ->
82
?ssh_assert(S >= 0 andalso S =< N-1, out_of_range),
83
ssh_math:ipow(S, E, N).
87
%% rsaes_oaep_encrypt(Public, M) ->
88
%% rsaes_oaep_encrypt(Public, M, <<>>).
90
%% rsaes_oaep_encrypt(Public=#ssh_key { public={N,_E}}, M, L) ->
91
%% ?ssh_assert(size(L) =< 16#ffffffffffffffff, label_to_long),
92
%% K = (ssh_bits:isize(N)+7) div 8,
95
%% ?ssh_assert(MLen =< K - 2*?HLen - 2, message_to_long),
97
%% PS = ssh_bits:fill_bits(K - MLen - 2*?HLen - 2, 0),
98
%% DB = <<LHash/binary, PS/binary, 16#01, M/binary>>,
99
%% Seed = ssh_bits:random(?HLen),
100
%% DbMask = ?MGF(Seed, K - ?HLen - 1),
101
%% MaskedDB = ssh_bits:xor_bits(DB, DbMask),
102
%% SeedMask = ?MGF(MaskedDB, ?HLen),
103
%% MaskedSeed = ssh_bits:xor_bits(Seed, SeedMask),
104
%% EM = <<16#00, MaskedSeed/binary, MaskedDB/binary>>,
106
%% C = rsaep(Public, Mc),
109
%% rsaes_oaep_decrypt(Key, C) ->
110
%% rsaes_oaep_decrypt(Key, C, <<>>).
112
%% rsaes_oaep_decrypt(Private=#ssh_key { public={N,_},private={_,_}},Cb,L) ->
113
%% ?ssh_assert(size(L) =< 16#ffffffffffffffff, label_to_long),
114
%% K = (ssh_bits:isize(N)+7) div 8,
115
%% ?ssh_assert(K == 2*?HLen + 2, decryption_error),
117
%% M = rsadp(Private, C),
120
%% MLen = K - ?HLen -1,
122
%% <<16#00, MaskedSeed:?HLen/binary, MaskedDB:MLen>> ->
123
%% SeedMask = ?MGF(MaskedDB, ?HLen),
124
%% Seed = ssh_bits:xor_bits(MaskedSeed, SeedMask),
125
%% DbMask = ?MGF(Seed, K - ?HLen - 1),
126
%% DB = ssh_bits:xor_bits(MaskedDB, DbMask),
127
%% PSLen = K - MLen - 2*?HLen - 2,
129
%% <<LHash:?HLen, _PS:PSLen/binary, 16#01, M/binary>> ->
132
%% exit(decryption_error)
135
%% exit(decryption_error)
139
%% rsaes_pkcs1_v1_5_encrypt(Public=#ssh_key { public={N,_}}, M) ->
140
%% K = (ssh_bits:isize(N)+7) div 8,
142
%% ?ssh_assert(MLen =< K - 11, message_to_long),
143
%% PS = ssh_bits:random(K - MLen - 3),
144
%% EM = <<16#00,16#02,PS/binary,16#00,M/binary>>,
146
%% C = rsaep(Public, Mc),
150
%% rsaes_pkcs1_v1_5_decrypt(Private=#ssh_key { public={N,_},private={_,_}},
152
%% K = (ssh_bits:isize(N)+7) div 8,
154
%% ?ssh_assert(CLen == K andalso K >= 11, decryption_error),
156
%% M = rsadp(Private, C),
158
%% PSLen = K - CLen - 3,
160
%% <<16#00, 16#02, _PS:PSLen/binary, 16#00, M>> ->
163
%% exit(decryption_error)
166
%% rsassa_pss_sign(Private=#ssh_key { public={N,_},private={_,_}},Mb) ->
167
%% ModBits = ssh_bits:isize(N),
168
%% K = (ModBits+7) div 8,
169
%% EM = emsa_pss_encode(Mb, ModBits - 1),
171
%% S = rsasp1(Private, M),
174
%% rsassa_pss_verify(Public=#ssh_key { public={N,_E}},Mb,Sb) ->
175
%% ModBits = ssh_bits:isize(N),
176
%% K = (ModBits+7) div 8,
177
%% ?ssh_assert(size(Sb) == K, invalid_signature),
179
%% M = rsavp1(Public,S),
180
%% EMLen = (ModBits-1+7) div 8,
181
%% EM = i2osp(M, EMLen),
182
%% emsa_pss_verify(Mb, EM, ModBits-1).
185
rsassa_pkcs1_v1_5_sign(Private=#ssh_key { public={N,_},private={_,_D}},Mb) ->
186
K = (ssh_bits:isize(N)+7) div 8,
187
EM = emsa_pkcs1_v1_5_encode(Mb, K),
189
S = rsasp1(Private, M),
192
rsassa_pkcs1_v1_5_verify(Public=#ssh_key { public={N,_E}}, Mb, Sb) ->
193
K = (ssh_bits:isize(N)+7) div 8,
194
?ssh_assert(size(Sb) == K, invalid_signature),
196
M = rsavp1(Public, S),
198
?dbg(true, "verify K=~p S=~w\nM=~w\nEM=~w\n", [K, S, M, EM]),
199
case emsa_pkcs1_v1_5_encode(Mb, K) of
201
_S -> {error, invalid_signature} % exit(invalid_signature)
205
emsa_pkcs1_v1_5_encode(M, EMLen) ->
207
%% Must use speical xxNull types here!
208
Alg = #'AlgorithmNull' { algorithm = ?'id-sha1',
210
{ok,TCode} = asn1rt:encode('PKCS-1', 'DigestInfoNull',
211
#'DigestInfoNull' { digestAlgorithm = Alg,
213
T = list_to_binary(TCode),
215
?ssh_assert(EMLen >= TLen + 11, message_to_short),
216
PS = ssh_bits:fill_bits(EMLen - TLen - 3, 16#ff),
217
<<16#00, 16#01, PS/binary, 16#00, T/binary>>.
220
%% emsa_pss_encode(M, EMBits) ->
221
%% emsa_pss_encode(M, EMBits, 0).
223
%% emsa_pss_encode(M, EMBits, SLen) ->
224
%% ?ssh_assert(size(M) =< 16#ffffffffffffffff, message_to_long),
225
%% EMLen = (EMBits + 7) div 8,
227
%% ?ssh_assert(EMLen >= ?HLen + SLen + 2, encoding_error),
228
%% Salt = ssh_bits:random(SLen),
229
%% M1 = [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
232
%% PS = ssh_bits:fill_bits(EMLen-SLen-?HLen-2, 0),
233
%% DB = <<PS/binary, 16#01, Salt/binary>>,
234
%% DbMask = ?MGF(H, EMLen - ?HLen -1),
235
%% MaskedDB = ssh_bits:xor_bits(DB, DbMask),
236
%% ZLen = 8*EMLen - EMBits,
237
%% NZLen = (8 - (ZLen rem 8)) rem 8,
238
%% <<_:ZLen, NZ:NZLen, MaskedDB1/binary>> = MaskedDB,
239
%% MaskedDB2 = <<0:ZLen, NZ:NZLen, MaskedDB1/binary>>,
240
%% <<MaskedDB2/binary, H/binary, 16#BC>>.
243
%% emsa_pss_verify(M, EM, EMBits) ->
244
%% emsa_pss_verify(M, EM, EMBits, 0).
246
%% emsa_pss_verify(M, EM, EMBits, SLen) ->
247
%% ?ssh_assert(size(M) =< 16#ffffffffffffffff, message_to_long),
248
%% EMLen = (EMBits + 7) div 8,
250
%% ?ssh_assert(EMLen >= ?HLen + SLen + 2, inconsistent),
251
%% MaskLen = (EMLen - ?HLen - 1)-1,
252
%% ZLen = 8*EMLen - EMBits,
253
%% NZLen = (8 - (ZLen rem 8)) rem 8,
255
%% <<0:ZLen,Nz:NZLen,MaskedDB1:MaskLen/binary, H:?HLen/binary, 16#BC>> ->
256
%% MaskedDB = <<0:ZLen,Nz:NZLen,MaskedDB1/binary>>,
257
%% DbMask = ?MGF(H, EMLen - ?HLen - 1),
258
%% DB = ssh_bits:xor_bits(MaskedDB, DbMask),
259
%% PSLen1 = (EMLen - SLen - ?HLen - 2) - 1,
260
%% PS = ssh_bits:fill_bits(PSLen1, 0),
262
%% <<_:ZLen,0:NZLen,PS:PSLen1/binary,16#01,Salt:SLen/binary>> ->
263
%% M1 = [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
267
%% _ -> exit(inconsistent)
270
%% exit(inconsistent)
273
%% exit(inconsistent)
278
%% Mask generating function MGF1
279
%% mgf1(MGFSeed, MaskLen) ->
280
%% T = mgf1_loop(0, ((MaskLen + ?HLen -1) div ?HLen) - 1, MGFSeed, ""),
281
%% <<R:MaskLen/binary, _/binary>> = T,
284
%% mgf1_loop(Counter, N, _, T) when Counter > N ->
285
%% list_to_binary(T);
286
%% mgf1_loop(Counter, N, MGFSeed, T) ->
287
%% C = i2osp(Counter, 4),
288
%% mgf1_loop(Counter+1, N, MGFSeed, [T, ?HASH([MGFSeed, C])]).