1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2005-2012. 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).
-include_lib("public_key/include/public_key.hrl").
-export([verify/3, sign/2]).
-export([alg_name/0]).
-include("ssh.hrl").
-define(MGF(Seed,Len), mgf1((Seed),(Len))).
-define(HASH(X), crypto:sha((X))).
-define(HLen, 20).
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).
%% sign1, M = message representative
rsasp1(#'RSAPrivateKey'{modulus = N, privateExponent = D}, M) ->
?ssh_assert((M >= 0 andalso M =< N-1), out_of_range),
ssh_math:ipow(M, D, N).
%% verify1, S =signature representative
rsavp1(#'RSAPublicKey'{publicExponent = E, modulus = N}, S) ->
?ssh_assert(S >= 0 andalso S =< N-1, out_of_range),
ssh_math:ipow(S, E, N).
rsassa_pkcs1_v1_5_sign(#'RSAPrivateKey'{modulus = N} = Private, 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_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(#'RSAPublicKey'{modulus = N} = Public, 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 -> true;
_S -> false
%%{error, 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 = <<>> },
TCode = public_key:der_encode('DigestInfoNull',
#'DigestInfoNull'{ digestAlgorithm = Alg,
digest = H }),
TLen = size(TCode),
?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, TCode/binary>>.
alg_name() ->
"ssh-rsa".
|