summaryrefslogtreecommitdiff
path: root/lib/ssh/src/ssh_rsa.erl
blob: 03c55319b7538099acba6a8305cc9d13715ef063 (plain)
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".