mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
Add support for DSA authentication in SSH2, following clever ideas
on how to get round the problem of generating a good k. [originally from svn r1284]
This commit is contained in:
parent
486685c89a
commit
d345ebc2a5
63
Makefile
63
Makefile
@ -104,16 +104,16 @@ MOBJ2 = tree234.$(OBJ)
|
|||||||
OBJS1 = sshcrc.$(OBJ) sshdes.$(OBJ) sshmd5.$(OBJ) sshrsa.$(OBJ) sshrand.$(OBJ)
|
OBJS1 = sshcrc.$(OBJ) sshdes.$(OBJ) sshmd5.$(OBJ) sshrsa.$(OBJ) sshrand.$(OBJ)
|
||||||
OBJS2 = sshsha.$(OBJ) sshblowf.$(OBJ) noise.$(OBJ) sshdh.$(OBJ) sshdss.$(OBJ)
|
OBJS2 = sshsha.$(OBJ) sshblowf.$(OBJ) noise.$(OBJ) sshdh.$(OBJ) sshdss.$(OBJ)
|
||||||
OBJS3 = sshbn.$(OBJ) sshpubk.$(OBJ) ssh.$(OBJ) pageantc.$(OBJ) sshzlib.$(OBJ)
|
OBJS3 = sshbn.$(OBJ) sshpubk.$(OBJ) ssh.$(OBJ) pageantc.$(OBJ) sshzlib.$(OBJ)
|
||||||
OBJS4 = x11fwd.$(OBJ) portfwd.$(OBJ) sshaes.$(OBJ)
|
OBJS4 = x11fwd.$(OBJ) portfwd.$(OBJ) sshaes.$(OBJ) sshsh512.$(OBJ)
|
||||||
##-- objects pageant
|
##-- objects pageant
|
||||||
PAGE1 = pageant.$(OBJ) sshrsa.$(OBJ) sshpubk.$(OBJ) sshdes.$(OBJ) sshbn.$(OBJ)
|
PAGE1 = pageant.$(OBJ) sshrsa.$(OBJ) sshpubk.$(OBJ) sshdes.$(OBJ) sshbn.$(OBJ)
|
||||||
PAGE2 = sshmd5.$(OBJ) version.$(OBJ) tree234.$(OBJ) misc.$(OBJ) sshaes.$(OBJ)
|
PAGE2 = sshmd5.$(OBJ) version.$(OBJ) tree234.$(OBJ) misc.$(OBJ) sshaes.$(OBJ)
|
||||||
PAGE3 = sshsha.$(OBJ) pageantc.$(OBJ)
|
PAGE3 = sshsha.$(OBJ) pageantc.$(OBJ) sshdss.$(OBJ) sshsh512.$(OBJ)
|
||||||
##-- objects puttygen
|
##-- objects puttygen
|
||||||
GEN1 = puttygen.$(OBJ) sshrsag.$(OBJ) sshprime.$(OBJ) sshdes.$(OBJ)
|
GEN1 = puttygen.$(OBJ) sshrsag.$(OBJ) sshdssg.$(OBJ) sshprime.$(OBJ)
|
||||||
GEN2 = sshbn.$(OBJ) sshmd5.$(OBJ) version.$(OBJ) sshrand.$(OBJ) noise.$(OBJ)
|
GEN2 = sshdes.$(OBJ) sshbn.$(OBJ) sshmd5.$(OBJ) version.$(OBJ) sshrand.$(OBJ)
|
||||||
GEN3 = sshsha.$(OBJ) winstore.$(OBJ) misc.$(OBJ) winctrls.$(OBJ)
|
GEN3 = noise.$(OBJ) sshsha.$(OBJ) winstore.$(OBJ) misc.$(OBJ) winctrls.$(OBJ)
|
||||||
GEN4 = sshrsa.$(OBJ) sshpubk.$(OBJ) sshaes.$(OBJ)
|
GEN4 = sshrsa.$(OBJ) sshdss.$(OBJ) sshpubk.$(OBJ) sshaes.$(OBJ) sshsh512.$(OBJ)
|
||||||
##-- resources putty puttytel
|
##-- resources putty puttytel
|
||||||
PRESRC = win_res.$(RES)
|
PRESRC = win_res.$(RES)
|
||||||
##-- resources pageant
|
##-- resources pageant
|
||||||
@ -273,57 +273,60 @@ plink.rsp: makefile
|
|||||||
be_all.$(OBJ): be_all.c network.h misc.h puttymem.h putty.h
|
be_all.$(OBJ): be_all.c network.h misc.h puttymem.h putty.h
|
||||||
be_none.$(OBJ): be_none.c network.h misc.h puttymem.h putty.h
|
be_none.$(OBJ): be_none.c network.h misc.h puttymem.h putty.h
|
||||||
be_nossh.$(OBJ): be_nossh.c network.h misc.h puttymem.h putty.h
|
be_nossh.$(OBJ): be_nossh.c network.h misc.h puttymem.h putty.h
|
||||||
ber.$(OBJ): ber.c network.h asn.h misc.h asnerror.h puttymem.h ssh.h putty.h
|
ber.$(OBJ): ber.c network.h asn.h misc.h asnerror.h int64.h puttymem.h ssh.h putty.h
|
||||||
cert.$(OBJ): cert.c asn.h asnerror.h misc.h puttymem.h cert.h crypto.h
|
cert.$(OBJ): cert.c asn.h asnerror.h misc.h puttymem.h cert.h crypto.h
|
||||||
|
debug.$(OBJ): debug.c debug.h
|
||||||
int64.$(OBJ): int64.c int64.h
|
int64.$(OBJ): int64.c int64.h
|
||||||
ldisc.$(OBJ): ldisc.c network.h misc.h puttymem.h putty.h
|
ldisc.$(OBJ): ldisc.c network.h misc.h puttymem.h putty.h
|
||||||
misc.$(OBJ): misc.c network.h misc.h puttymem.h putty.h
|
misc.$(OBJ): misc.c network.h misc.h puttymem.h putty.h
|
||||||
mscrypto.$(OBJ): mscrypto.c network.h puttymem.h ssh.h
|
mscrypto.$(OBJ): mscrypto.c network.h int64.h puttymem.h ssh.h
|
||||||
no_ssl.$(OBJ): no_ssl.c network.h misc.h puttymem.h putty.h
|
no_ssl.$(OBJ): no_ssl.c network.h misc.h puttymem.h putty.h
|
||||||
noise.$(OBJ): noise.c network.h misc.h puttymem.h storage.h ssh.h putty.h
|
noise.$(OBJ): noise.c network.h misc.h puttymem.h storage.h int64.h ssh.h putty.h
|
||||||
pageant.$(OBJ): pageant.c network.h puttymem.h ssh.h tree234.h
|
pageant.$(OBJ): pageant.c network.h int64.h puttymem.h ssh.h tree234.h
|
||||||
pageantc.$(OBJ): pageantc.c puttymem.h
|
pageantc.$(OBJ): pageantc.c puttymem.h
|
||||||
plink.$(OBJ): plink.c network.h misc.h puttymem.h storage.h putty.h tree234.h
|
plink.$(OBJ): plink.c network.h misc.h puttymem.h storage.h putty.h tree234.h
|
||||||
portfwd.$(OBJ): portfwd.c network.h misc.h puttymem.h ssh.h putty.h
|
portfwd.$(OBJ): portfwd.c network.h misc.h int64.h puttymem.h ssh.h putty.h
|
||||||
psftp.$(OBJ): psftp.c network.h misc.h sftp.h ssh.h storage.h int64.h puttymem.h putty.h
|
psftp.$(OBJ): psftp.c network.h misc.h sftp.h ssh.h storage.h int64.h puttymem.h putty.h
|
||||||
puttygen.$(OBJ): puttygen.c network.h misc.h puttymem.h winstuff.h ssh.h putty.h
|
puttygen.$(OBJ): puttygen.c network.h misc.h int64.h puttymem.h winstuff.h ssh.h putty.h
|
||||||
raw.$(OBJ): raw.c network.h misc.h puttymem.h putty.h
|
raw.$(OBJ): raw.c network.h misc.h puttymem.h putty.h
|
||||||
rlogin.$(OBJ): rlogin.c network.h misc.h puttymem.h putty.h
|
rlogin.$(OBJ): rlogin.c network.h misc.h puttymem.h putty.h
|
||||||
scp.$(OBJ): scp.c network.h misc.h sftp.h ssh.h storage.h puttymem.h int64.h putty.h winstuff.h
|
scp.$(OBJ): scp.c network.h misc.h sftp.h ssh.h storage.h puttymem.h int64.h putty.h winstuff.h
|
||||||
settings.$(OBJ): settings.c network.h misc.h puttymem.h storage.h putty.h
|
settings.$(OBJ): settings.c network.h misc.h puttymem.h storage.h putty.h
|
||||||
sftp.$(OBJ): sftp.c sftp.h int64.h
|
sftp.$(OBJ): sftp.c sftp.h int64.h
|
||||||
sizetip.$(OBJ): sizetip.c network.h misc.h puttymem.h winstuff.h putty.h
|
sizetip.$(OBJ): sizetip.c network.h misc.h puttymem.h winstuff.h putty.h
|
||||||
ssh.$(OBJ): ssh.c network.h misc.h puttymem.h ssh.h putty.h tree234.h
|
ssh.$(OBJ): ssh.c network.h misc.h int64.h puttymem.h ssh.h putty.h tree234.h
|
||||||
sshaes.$(OBJ): sshaes.c network.h puttymem.h ssh.h
|
sshaes.$(OBJ): sshaes.c network.h int64.h puttymem.h ssh.h
|
||||||
sshblowf.$(OBJ): sshblowf.c network.h puttymem.h ssh.h
|
sshblowf.$(OBJ): sshblowf.c network.h int64.h puttymem.h ssh.h
|
||||||
sshbn.$(OBJ): sshbn.c network.h misc.h puttymem.h ssh.h putty.h
|
sshbn.$(OBJ): sshbn.c network.h misc.h int64.h puttymem.h ssh.h putty.h
|
||||||
sshcrc.$(OBJ): sshcrc.c
|
sshcrc.$(OBJ): sshcrc.c
|
||||||
sshdes.$(OBJ): sshdes.c network.h puttymem.h ssh.h
|
sshdes.$(OBJ): sshdes.c network.h int64.h puttymem.h ssh.h
|
||||||
sshdh.$(OBJ): sshdh.c network.h puttymem.h ssh.h
|
sshdh.$(OBJ): sshdh.c network.h int64.h puttymem.h ssh.h
|
||||||
sshdss.$(OBJ): sshdss.c network.h puttymem.h ssh.h
|
sshdss.$(OBJ): sshdss.c network.h misc.h int64.h puttymem.h ssh.h
|
||||||
sshmd5.$(OBJ): sshmd5.c network.h puttymem.h ssh.h
|
sshdssg.$(OBJ): sshdssg.c network.h misc.h int64.h puttymem.h ssh.h
|
||||||
sshprime.$(OBJ): sshprime.c network.h puttymem.h ssh.h
|
sshmd5.$(OBJ): sshmd5.c network.h int64.h puttymem.h ssh.h
|
||||||
sshpubk.$(OBJ): sshpubk.c network.h puttymem.h ssh.h
|
sshprime.$(OBJ): sshprime.c network.h int64.h puttymem.h ssh.h
|
||||||
sshrand.$(OBJ): sshrand.c network.h puttymem.h ssh.h
|
sshpubk.$(OBJ): sshpubk.c network.h int64.h puttymem.h ssh.h
|
||||||
sshrsa.$(OBJ): sshrsa.c network.h puttymem.h ssh.h
|
sshrand.$(OBJ): sshrand.c network.h int64.h puttymem.h ssh.h
|
||||||
sshrsag.$(OBJ): sshrsag.c network.h puttymem.h ssh.h
|
sshrsa.$(OBJ): sshrsa.c network.h int64.h puttymem.h ssh.h
|
||||||
sshsha.$(OBJ): sshsha.c network.h puttymem.h ssh.h
|
sshrsag.$(OBJ): sshrsag.c network.h int64.h puttymem.h ssh.h
|
||||||
sshzlib.$(OBJ): sshzlib.c network.h puttymem.h ssh.h
|
sshsh512.$(OBJ): sshsh512.c network.h int64.h puttymem.h ssh.h
|
||||||
|
sshsha.$(OBJ): sshsha.c network.h int64.h puttymem.h ssh.h
|
||||||
|
sshzlib.$(OBJ): sshzlib.c network.h int64.h puttymem.h ssh.h
|
||||||
ssl.$(OBJ): ssl.c network.h asnerror.h misc.h cert.h crypto.h ssl.h int64.h puttymem.h
|
ssl.$(OBJ): ssl.c network.h asnerror.h misc.h cert.h crypto.h ssl.h int64.h puttymem.h
|
||||||
telnet.$(OBJ): telnet.c network.h misc.h puttymem.h putty.h
|
telnet.$(OBJ): telnet.c network.h misc.h puttymem.h putty.h
|
||||||
terminal.$(OBJ): terminal.c network.h misc.h puttymem.h putty.h tree234.h
|
terminal.$(OBJ): terminal.c network.h misc.h puttymem.h putty.h tree234.h
|
||||||
test.$(OBJ): test.c network.h puttymem.h ssh.h
|
test.$(OBJ): test.c network.h int64.h puttymem.h ssh.h
|
||||||
tree234.$(OBJ): tree234.c tree234.h
|
tree234.$(OBJ): tree234.c tree234.h
|
||||||
unicode.$(OBJ): unicode.c network.h misc.h puttymem.h putty.h
|
unicode.$(OBJ): unicode.c network.h misc.h puttymem.h putty.h
|
||||||
version.$(OBJ): version.c
|
version.$(OBJ): version.c
|
||||||
wcwidth.$(OBJ): wcwidth.c
|
wcwidth.$(OBJ): wcwidth.c
|
||||||
wildcard.$(OBJ): wildcard.c
|
wildcard.$(OBJ): wildcard.c
|
||||||
winctrls.$(OBJ): winctrls.c network.h misc.h puttymem.h putty.h winstuff.h
|
winctrls.$(OBJ): winctrls.c network.h misc.h puttymem.h putty.h winstuff.h
|
||||||
windlg.$(OBJ): windlg.c network.h misc.h ssh.h storage.h puttymem.h putty.h winstuff.h win_res.h
|
windlg.$(OBJ): windlg.c network.h misc.h ssh.h storage.h puttymem.h int64.h putty.h winstuff.h win_res.h
|
||||||
window.$(OBJ): window.c network.h misc.h puttymem.h storage.h winstuff.h putty.h win_res.h
|
window.$(OBJ): window.c network.h misc.h puttymem.h storage.h winstuff.h putty.h win_res.h
|
||||||
winnet.$(OBJ): winnet.c network.h misc.h puttymem.h putty.h tree234.h
|
winnet.$(OBJ): winnet.c network.h misc.h puttymem.h putty.h tree234.h
|
||||||
winstore.$(OBJ): winstore.c network.h misc.h puttymem.h storage.h putty.h
|
winstore.$(OBJ): winstore.c network.h misc.h puttymem.h storage.h putty.h
|
||||||
x11fwd.$(OBJ): x11fwd.c network.h misc.h puttymem.h ssh.h putty.h
|
x11fwd.$(OBJ): x11fwd.c network.h misc.h int64.h puttymem.h ssh.h putty.h
|
||||||
##--
|
##--
|
||||||
|
|
||||||
# Hack to force version.obj to be rebuilt always
|
# Hack to force version.obj to be rebuilt always
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
\versionid $Id: pubkey.but,v 1.4 2001/09/22 15:36:44 simon Exp $
|
\versionid $Id: pubkey.but,v 1.5 2001/09/22 20:52:21 simon Exp $
|
||||||
|
|
||||||
\# FIXME: passphrases, examples (e.g what does a key for pasting into
|
\# FIXME: passphrases, examples (e.g what does a key for pasting into
|
||||||
\# authorized_keys look like?), index entries, links.
|
\# authorized_keys look like?), index entries, links.
|
||||||
@ -59,7 +59,37 @@ shuts down, without ever having stored your decrypted private key on
|
|||||||
disk. Many people feel this is a good compromise between security
|
disk. Many people feel this is a good compromise between security
|
||||||
and convenience. See \k{pageant} for further details.
|
and convenience. See \k{pageant} for further details.
|
||||||
|
|
||||||
\H{pubkey-puttygen} PuTTYgen: RSA key generator for PuTTY
|
\S{pubkey-types} Different types of public key
|
||||||
|
|
||||||
|
The PuTTY key generator, described in \k{pubkey-puttygen}, offers
|
||||||
|
you the opportunity to generate several types of key pair:
|
||||||
|
|
||||||
|
\b An RSA key for use with the SSH 1 protocol.
|
||||||
|
\b An RSA key for use with the SSH 2 protocol.
|
||||||
|
\b A DSA key for use with the SSH 2 protocol.
|
||||||
|
|
||||||
|
The SSH 1 protocol only supports RSA keys; if you will be connecting
|
||||||
|
using the SSH 1 protocol, you must select the first key type or your
|
||||||
|
key will be completely useless.
|
||||||
|
|
||||||
|
SSH 2 supports more than one key type. The two types supported by
|
||||||
|
PuTTY are RSA and DSA.
|
||||||
|
|
||||||
|
The PuTTY developers \e{strongly} recommend you use RSA. DSA has an
|
||||||
|
intrinsic weakness which makes it very easy to create a signature
|
||||||
|
which contains enough information to give away the \e{private} key!
|
||||||
|
This would allow an attacker to pretend to be you for any number of
|
||||||
|
future sessions. PuTTY's implementation has taken very careful
|
||||||
|
precautions to avoid this weakness, but we cannot be 100% certain we
|
||||||
|
have managed it, and if you have the choice we strongly recommend
|
||||||
|
using RSA keys instead.
|
||||||
|
|
||||||
|
If you really need to connect to an SSH server which only supports
|
||||||
|
DSA, then you probably have no choice but to use DSA. If you do use
|
||||||
|
DSA, we recommend you do not use the same key to authenticate with
|
||||||
|
more than one server.
|
||||||
|
|
||||||
|
\H{pubkey-puttygen} PuTTYgen: Key generator for PuTTY
|
||||||
|
|
||||||
PuTTYgen is a key generator. It generates pairs of public and private
|
PuTTYgen is a key generator. It generates pairs of public and private
|
||||||
keys to be used with PuTTY, PSCP, and Plink, as well as the PuTTY
|
keys to be used with PuTTY, PSCP, and Plink, as well as the PuTTY
|
||||||
@ -73,8 +103,9 @@ existing private key.
|
|||||||
\S{pubkey-puttygen-generate} Generate a new key
|
\S{pubkey-puttygen-generate} Generate a new key
|
||||||
|
|
||||||
Before generating a new key you have to choose the strength of the
|
Before generating a new key you have to choose the strength of the
|
||||||
encryption. With \e{Parameters} you define the strength of the key. The
|
encryption, and the type of the key (see \k{pubkey-types}). With
|
||||||
default of 1024 should be OK for most users.
|
\e{Parameters} you define the strength of the key. The default of
|
||||||
|
1024 should be OK for most users.
|
||||||
|
|
||||||
Pressing the \e{Generate} button starts the process of generating a
|
Pressing the \e{Generate} button starts the process of generating a
|
||||||
new key pair. You then have to move the mouse over the blank area in
|
new key pair. You then have to move the mouse over the blank area in
|
||||||
@ -116,16 +147,36 @@ private key this way. Just modify the values and \e{Save} the key.
|
|||||||
|
|
||||||
Connect to your SSH server using PuTTY with the SSH protocol. When the
|
Connect to your SSH server using PuTTY with the SSH protocol. When the
|
||||||
connection succeeds you will be prompted for your user name and
|
connection succeeds you will be prompted for your user name and
|
||||||
password to login. Once logged in change into the \c{.ssh} directory
|
password to login. Once logged in, you must configure the server to
|
||||||
and open the file \c{authorized_keys} with your favorite editor (you
|
accept your public key for authentication:
|
||||||
may have to create this file if this is the first key to add).
|
|
||||||
|
|
||||||
Switch to the PuTTYgen window and select all of the content below
|
\b If your server is using the SSH 1 protocol, you should change
|
||||||
\e{Public key for pasting into authorized_keys file}, copy it to the
|
into the \c{.ssh} directory and open the file \c{authorized_keys}
|
||||||
clipboard (\c{Ctrl+C}). Then, switch back to the PuTTY window and
|
with your favorite editor. (You may have to create this file if this
|
||||||
insert the data into the open file. Save the file.
|
is the first key you have put in it). Then switch to the PuTTYgen
|
||||||
|
window, select all of the text in the \e{Public key for pasting into
|
||||||
|
authorized_keys file} box, and copy it to the clipboard
|
||||||
|
(\c{Ctrl+C}). Then, switch back to the PuTTY window and insert the
|
||||||
|
data into the open file, making sure it ends up all on one line.
|
||||||
|
Save the file.
|
||||||
|
|
||||||
From now on you can use the private key for authentication to this
|
\b If your server is OpenSSH and is using the SSH 2 protocol, you
|
||||||
host. Either select the private key in PuTTY's \e{Connection},
|
should follow the same instructions except that the file will be
|
||||||
\e{SSH} panel: \e{Private key file for authentication} dialog or use
|
called \c{authorized_keys2}.
|
||||||
it with Pageant as described in \k{pageant}.
|
|
||||||
|
\b If your server is \cw{ssh.com}'s SSH 2 product, you need to save
|
||||||
|
a \e{public} key file from PuTTYgen, and copy that into the
|
||||||
|
\c{.ssh2} directory on the server. Then you should go into that
|
||||||
|
\c{.ssh2} directory, and edit (or create) a file called
|
||||||
|
\c{authorization}. In this file you should put a line like \c{Key
|
||||||
|
mykey.pub}, with \c{mykey.pub} replaced by the name of your key
|
||||||
|
file.
|
||||||
|
|
||||||
|
\b For other SSH server software, you should refer to the manual for
|
||||||
|
that server.
|
||||||
|
|
||||||
|
From now on you should be able to use the private key for
|
||||||
|
authentication to this host. Either select the private key in
|
||||||
|
PuTTY's \e{Connection}, \e{SSH} panel: \e{Private key file for
|
||||||
|
authentication} dialog or use it with Pageant as described in
|
||||||
|
\k{pageant}.
|
||||||
|
@ -613,7 +613,7 @@ static void answer_msg(void *msg)
|
|||||||
break;
|
break;
|
||||||
case SSH2_AGENTC_SIGN_REQUEST:
|
case SSH2_AGENTC_SIGN_REQUEST:
|
||||||
/*
|
/*
|
||||||
* Reply with either SSH2_AGENT_RSA_RESPONSE or
|
* Reply with either SSH2_AGENT_SIGN_RESPONSE or
|
||||||
* SSH_AGENT_FAILURE, depending on whether we have that key
|
* SSH_AGENT_FAILURE, depending on whether we have that key
|
||||||
* or not.
|
* or not.
|
||||||
*/
|
*/
|
||||||
@ -696,6 +696,8 @@ static void answer_msg(void *msg)
|
|||||||
/* Add further algorithm names here. */
|
/* Add further algorithm names here. */
|
||||||
if (alglen == 7 && !memcmp(alg, "ssh-rsa", 7))
|
if (alglen == 7 && !memcmp(alg, "ssh-rsa", 7))
|
||||||
key->alg = &ssh_rsa;
|
key->alg = &ssh_rsa;
|
||||||
|
else if (alglen == 7 && !memcmp(alg, "ssh-dss", 7))
|
||||||
|
key->alg = &ssh_dss;
|
||||||
else {
|
else {
|
||||||
sfree(key);
|
sfree(key);
|
||||||
goto failure;
|
goto failure;
|
||||||
|
139
puttygen.c
139
puttygen.c
@ -21,72 +21,72 @@
|
|||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
* Progress report code. This is really horrible :-)
|
* Progress report code. This is really horrible :-)
|
||||||
*/
|
*/
|
||||||
#define PHASE1TOTAL 0x10000
|
#define PROGRESSRANGE 65535
|
||||||
#define PHASE2TOTAL 0x10000
|
#define MAXPHASE 5
|
||||||
#define PHASE3TOTAL 0x04000
|
|
||||||
#define PHASE1START 0
|
|
||||||
#define PHASE2START (PHASE1TOTAL)
|
|
||||||
#define PHASE3START (PHASE1TOTAL + PHASE2TOTAL)
|
|
||||||
#define TOTALTOTAL (PHASE1TOTAL + PHASE2TOTAL + PHASE3TOTAL)
|
|
||||||
#define PROGRESSBIGRANGE 65535
|
|
||||||
#define DIVISOR ((TOTALTOTAL + PROGRESSBIGRANGE - 1) / PROGRESSBIGRANGE)
|
|
||||||
#define PROGRESSRANGE (TOTALTOTAL / DIVISOR)
|
|
||||||
struct progress {
|
struct progress {
|
||||||
unsigned phase1param, phase1current, phase1n;
|
int nphases;
|
||||||
unsigned phase2param, phase2current, phase2n;
|
struct {
|
||||||
unsigned phase3mult;
|
int exponential;
|
||||||
|
unsigned startpoint, total;
|
||||||
|
unsigned param, current, n; /* if exponential */
|
||||||
|
unsigned mult; /* if linear */
|
||||||
|
} phases[MAXPHASE];
|
||||||
|
unsigned total, divisor, range;
|
||||||
HWND progbar;
|
HWND progbar;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void progress_update(void *param, int phase, int iprogress)
|
static void progress_update(void *param, int action, int phase, int iprogress)
|
||||||
{
|
{
|
||||||
struct progress *p = (struct progress *) param;
|
struct progress *p = (struct progress *) param;
|
||||||
unsigned progress = iprogress;
|
unsigned progress = iprogress;
|
||||||
int position;
|
int position;
|
||||||
|
|
||||||
switch (phase) {
|
if (action < PROGFN_READY && p->nphases < phase)
|
||||||
case -1:
|
p->nphases = phase;
|
||||||
p->phase1param = 0x10000 + progress;
|
switch (action) {
|
||||||
p->phase1current = 0x10000;
|
case PROGFN_LIN_PHASE:
|
||||||
p->phase1n = 0;
|
p->phases[phase-1].exponential = 0;
|
||||||
return;
|
p->phases[phase-1].mult = p->phases[phase].total / progress;
|
||||||
case -2:
|
|
||||||
p->phase2param = 0x10000 + progress;
|
|
||||||
p->phase2current = 0x10000;
|
|
||||||
p->phase2n = 0;
|
|
||||||
return;
|
|
||||||
case -3:
|
|
||||||
p->phase3mult = PHASE3TOTAL / progress;
|
|
||||||
return;
|
|
||||||
case 1:
|
|
||||||
while (p->phase1n < progress) {
|
|
||||||
p->phase1n++;
|
|
||||||
p->phase1current *= p->phase1param;
|
|
||||||
p->phase1current /= 0x10000;
|
|
||||||
}
|
|
||||||
position = PHASE1START + 0x10000 - p->phase1current;
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case PROGFN_EXP_PHASE:
|
||||||
while (p->phase2n < progress) {
|
p->phases[phase-1].exponential = 1;
|
||||||
p->phase2n++;
|
p->phases[phase-1].param = 0x10000 + progress;
|
||||||
p->phase2current *= p->phase2param;
|
p->phases[phase-1].current = p->phases[phase-1].total;
|
||||||
p->phase2current /= 0x10000;
|
p->phases[phase-1].n = 0;
|
||||||
}
|
|
||||||
position = PHASE2START + 0x10000 - p->phase2current;
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
case PROGFN_PHASE_EXTENT:
|
||||||
position = PHASE3START + progress * p->phase3mult;
|
p->phases[phase-1].total = progress;
|
||||||
|
break;
|
||||||
|
case PROGFN_READY:
|
||||||
|
{
|
||||||
|
unsigned total = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < p->nphases; i++) {
|
||||||
|
p->phases[i].startpoint = total;
|
||||||
|
total += p->phases[i].total;
|
||||||
|
}
|
||||||
|
p->total = total;
|
||||||
|
p->divisor = ((p->total + PROGRESSRANGE - 1) / PROGRESSRANGE);
|
||||||
|
p->range = p->total / p->divisor;
|
||||||
|
SendMessage(p->progbar, PBM_SETRANGE, 0, MAKELPARAM(0, p->range));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PROGFN_PROGRESS:
|
||||||
|
if (p->phases[phase-1].exponential) {
|
||||||
|
while (p->phases[phase-1].n < progress) {
|
||||||
|
p->phases[phase-1].n++;
|
||||||
|
p->phases[phase-1].current *= p->phases[phase-1].param;
|
||||||
|
p->phases[phase-1].current /= 0x10000;
|
||||||
|
}
|
||||||
|
position = (p->phases[phase-1].startpoint +
|
||||||
|
p->phases[phase-1].total - p->phases[phase-1].current);
|
||||||
|
} else {
|
||||||
|
position = (p->phases[phase-1].startpoint +
|
||||||
|
progress * p->phases[phase-1].mult);
|
||||||
|
}
|
||||||
|
SendMessage(p->progbar, PBM_SETPOS, position / p->divisor, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
/*
|
|
||||||
* Shouldn't happen, but having a default clause placates
|
|
||||||
* gcc -Wall, which would otherwise complain that
|
|
||||||
* `position' might be used uninitialised.
|
|
||||||
*/
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SendMessage(p->progbar, PBM_SETPOS, position / DIVISOR, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern char ver[];
|
extern char ver[];
|
||||||
@ -291,7 +291,9 @@ struct rsa_key_thread_params {
|
|||||||
HWND progressbar; /* notify this with progress */
|
HWND progressbar; /* notify this with progress */
|
||||||
HWND dialog; /* notify this on completion */
|
HWND dialog; /* notify this on completion */
|
||||||
int keysize; /* bits in key */
|
int keysize; /* bits in key */
|
||||||
|
int is_dsa;
|
||||||
struct RSAKey *key;
|
struct RSAKey *key;
|
||||||
|
struct dss_key *dsskey;
|
||||||
};
|
};
|
||||||
static DWORD WINAPI generate_rsa_key_thread(void *param)
|
static DWORD WINAPI generate_rsa_key_thread(void *param)
|
||||||
{
|
{
|
||||||
@ -300,6 +302,9 @@ static DWORD WINAPI generate_rsa_key_thread(void *param)
|
|||||||
struct progress prog;
|
struct progress prog;
|
||||||
prog.progbar = params->progressbar;
|
prog.progbar = params->progressbar;
|
||||||
|
|
||||||
|
if (params->is_dsa)
|
||||||
|
dsa_generate(params->dsskey, params->keysize, progress_update, &prog);
|
||||||
|
else
|
||||||
rsa_generate(params->key, params->keysize, progress_update, &prog);
|
rsa_generate(params->key, params->keysize, progress_update, &prog);
|
||||||
|
|
||||||
PostMessage(params->dialog, WM_DONEKEY, 0, 0);
|
PostMessage(params->dialog, WM_DONEKEY, 0, 0);
|
||||||
@ -314,11 +319,12 @@ struct MainDlgState {
|
|||||||
int key_exists;
|
int key_exists;
|
||||||
int entropy_got, entropy_required, entropy_size;
|
int entropy_got, entropy_required, entropy_size;
|
||||||
int keysize;
|
int keysize;
|
||||||
int ssh2;
|
int ssh2, is_dsa;
|
||||||
char **commentptr; /* points to key.comment or ssh2key.comment */
|
char **commentptr; /* points to key.comment or ssh2key.comment */
|
||||||
struct ssh2_userkey ssh2key;
|
struct ssh2_userkey ssh2key;
|
||||||
unsigned *entropy;
|
unsigned *entropy;
|
||||||
struct RSAKey key;
|
struct RSAKey key;
|
||||||
|
struct dss_key dsskey;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void hidemany(HWND hwnd, const int *ids, int hideit)
|
static void hidemany(HWND hwnd, const int *ids, int hideit)
|
||||||
@ -465,7 +471,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
|||||||
IDC_LOADSTATIC, IDC_LOAD,
|
IDC_LOADSTATIC, IDC_LOAD,
|
||||||
IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB,
|
IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB,
|
||||||
IDC_BOX_PARAMS,
|
IDC_BOX_PARAMS,
|
||||||
IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA,
|
IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA,
|
||||||
IDC_BITSSTATIC, IDC_BITS,
|
IDC_BITSSTATIC, IDC_BITS,
|
||||||
IDC_ABOUT,
|
IDC_ABOUT,
|
||||||
};
|
};
|
||||||
@ -511,7 +517,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
|||||||
{
|
{
|
||||||
struct ctlpos cp, cp2;
|
struct ctlpos cp, cp2;
|
||||||
|
|
||||||
/* Accelerators used: acglops1rb */
|
/* Accelerators used: acglops1rbd */
|
||||||
|
|
||||||
ctlposinit(&cp, hwnd, 10, 10, 10);
|
ctlposinit(&cp, hwnd, 10, 10, 10);
|
||||||
bartitle(&cp, "Public and private key generation for PuTTY",
|
bartitle(&cp, "Public and private key generation for PuTTY",
|
||||||
@ -547,9 +553,10 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
|||||||
"&Save private key", IDC_SAVE);
|
"&Save private key", IDC_SAVE);
|
||||||
endbox(&cp);
|
endbox(&cp);
|
||||||
beginbox(&cp, "Parameters", IDC_BOX_PARAMS);
|
beginbox(&cp, "Parameters", IDC_BOX_PARAMS);
|
||||||
radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 2,
|
radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 3,
|
||||||
"SSH&1 (RSA)", IDC_KEYSSH1,
|
"SSH&1 (RSA)", IDC_KEYSSH1,
|
||||||
"SSH2 &RSA", IDC_KEYSSH2RSA, NULL);
|
"SSH2 &RSA", IDC_KEYSSH2RSA,
|
||||||
|
"SSH2 &DSA", IDC_KEYSSH2DSA, NULL);
|
||||||
staticedit(&cp, "Number of &bits in a generated key:",
|
staticedit(&cp, "Number of &bits in a generated key:",
|
||||||
IDC_BITSSTATIC, IDC_BITS, 20);
|
IDC_BITSSTATIC, IDC_BITS, 20);
|
||||||
endbox(&cp);
|
endbox(&cp);
|
||||||
@ -599,7 +606,9 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
|||||||
params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS);
|
params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS);
|
||||||
params->dialog = hwnd;
|
params->dialog = hwnd;
|
||||||
params->keysize = state->keysize;
|
params->keysize = state->keysize;
|
||||||
|
params->is_dsa = state->is_dsa;
|
||||||
params->key = &state->key;
|
params->key = &state->key;
|
||||||
|
params->dsskey = &state->dsskey;
|
||||||
|
|
||||||
if (!CreateThread(NULL, 0, generate_rsa_key_thread,
|
if (!CreateThread(NULL, 0, generate_rsa_key_thread,
|
||||||
params, 0, &threadid)) {
|
params, 0, &threadid)) {
|
||||||
@ -652,6 +661,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
|||||||
state->keysize = DEFAULT_KEYSIZE;
|
state->keysize = DEFAULT_KEYSIZE;
|
||||||
/* If we ever introduce a new key type, check it here! */
|
/* If we ever introduce a new key type, check it here! */
|
||||||
state->ssh2 = !IsDlgButtonChecked(hwnd, IDC_KEYSSH1);
|
state->ssh2 = !IsDlgButtonChecked(hwnd, IDC_KEYSSH1);
|
||||||
|
state->is_dsa = IsDlgButtonChecked(hwnd, IDC_KEYSSH2DSA);
|
||||||
if (state->keysize < 256) {
|
if (state->keysize < 256) {
|
||||||
int ret = MessageBox(hwnd,
|
int ret = MessageBox(hwnd,
|
||||||
"PuTTYgen will not generate a key"
|
"PuTTYgen will not generate a key"
|
||||||
@ -937,8 +947,9 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
|||||||
state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
|
state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
|
||||||
state->generation_thread_exists = FALSE;
|
state->generation_thread_exists = FALSE;
|
||||||
state->key_exists = TRUE;
|
state->key_exists = TRUE;
|
||||||
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, PROGRESSRANGE,
|
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
|
||||||
0);
|
MAKELPARAM(0, PROGRESSRANGE));
|
||||||
|
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, PROGRESSRANGE, 0);
|
||||||
EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
|
EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
|
||||||
EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
|
EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
|
||||||
EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1);
|
EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1);
|
||||||
@ -947,8 +958,13 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
|||||||
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
|
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
|
||||||
EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
|
EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
|
||||||
if (state->ssh2) {
|
if (state->ssh2) {
|
||||||
|
if (state->is_dsa) {
|
||||||
|
state->ssh2key.data = &state->dsskey;
|
||||||
|
state->ssh2key.alg = &ssh_dss;
|
||||||
|
} else {
|
||||||
state->ssh2key.data = &state->key;
|
state->ssh2key.data = &state->key;
|
||||||
state->ssh2key.alg = &ssh_rsa;
|
state->ssh2key.alg = &ssh_rsa;
|
||||||
|
}
|
||||||
state->commentptr = &state->ssh2key.comment;
|
state->commentptr = &state->ssh2key.comment;
|
||||||
} else {
|
} else {
|
||||||
state->commentptr = &state->key.comment;
|
state->commentptr = &state->key.comment;
|
||||||
@ -965,6 +981,9 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
|||||||
struct tm *tm;
|
struct tm *tm;
|
||||||
time(&t);
|
time(&t);
|
||||||
tm = localtime(&t);
|
tm = localtime(&t);
|
||||||
|
if (state->is_dsa)
|
||||||
|
strftime(*state->commentptr, 30, "dsa-key-%Y%m%d", tm);
|
||||||
|
else
|
||||||
strftime(*state->commentptr, 30, "rsa-key-%Y%m%d", tm);
|
strftime(*state->commentptr, 30, "rsa-key-%Y%m%d", tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
38
ssh.h
38
ssh.h
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "puttymem.h"
|
#include "puttymem.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
#include "int64.h"
|
||||||
|
|
||||||
struct ssh_channel;
|
struct ssh_channel;
|
||||||
|
|
||||||
@ -48,6 +49,10 @@ struct RSAKey {
|
|||||||
char *comment;
|
char *comment;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dss_key {
|
||||||
|
Bignum p, q, g, y, x;
|
||||||
|
};
|
||||||
|
|
||||||
int makekey(unsigned char *data, struct RSAKey *result,
|
int makekey(unsigned char *data, struct RSAKey *result,
|
||||||
unsigned char **keystr, int order);
|
unsigned char **keystr, int order);
|
||||||
int makeprivate(unsigned char *data, struct RSAKey *result);
|
int makeprivate(unsigned char *data, struct RSAKey *result);
|
||||||
@ -92,12 +97,25 @@ typedef struct {
|
|||||||
int blkused;
|
int blkused;
|
||||||
uint32 lenhi, lenlo;
|
uint32 lenhi, lenlo;
|
||||||
} SHA_State;
|
} SHA_State;
|
||||||
|
|
||||||
void SHA_Init(SHA_State * s);
|
void SHA_Init(SHA_State * s);
|
||||||
void SHA_Bytes(SHA_State * s, void *p, int len);
|
void SHA_Bytes(SHA_State * s, void *p, int len);
|
||||||
void SHA_Final(SHA_State * s, unsigned char *output);
|
void SHA_Final(SHA_State * s, unsigned char *output);
|
||||||
void SHA_Simple(void *p, int len, unsigned char *output);
|
void SHA_Simple(void *p, int len, unsigned char *output);
|
||||||
|
|
||||||
|
void hmac_sha1_simple(void *key, int keylen, void *data, int datalen,
|
||||||
|
unsigned char *output);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64 h[8];
|
||||||
|
unsigned char block[128];
|
||||||
|
int blkused;
|
||||||
|
uint32 len[4];
|
||||||
|
} SHA512_State;
|
||||||
|
void SHA512_Init(SHA512_State * s);
|
||||||
|
void SHA512_Bytes(SHA512_State * s, const void *p, int len);
|
||||||
|
void SHA512_Final(SHA512_State * s, unsigned char *output);
|
||||||
|
void SHA512_Simple(const void *p, int len, unsigned char *output);
|
||||||
|
|
||||||
struct ssh_cipher {
|
struct ssh_cipher {
|
||||||
void (*sesskey) (unsigned char *key); /* for ssh 1 */
|
void (*sesskey) (unsigned char *key); /* for ssh 1 */
|
||||||
void (*encrypt) (unsigned char *blk, int len);
|
void (*encrypt) (unsigned char *blk, int len);
|
||||||
@ -219,7 +237,7 @@ void ssh_send_port_open(void *channel, char *hostname, int port, char *org);
|
|||||||
Bignum copybn(Bignum b);
|
Bignum copybn(Bignum b);
|
||||||
Bignum bn_power_2(int n);
|
Bignum bn_power_2(int n);
|
||||||
void bn_restore_invariant(Bignum b);
|
void bn_restore_invariant(Bignum b);
|
||||||
Bignum bignum_from_short(unsigned short n);
|
Bignum bignum_from_long(unsigned long n);
|
||||||
void freebn(Bignum b);
|
void freebn(Bignum b);
|
||||||
Bignum modpow(Bignum base, Bignum exp, Bignum mod);
|
Bignum modpow(Bignum base, Bignum exp, Bignum mod);
|
||||||
Bignum modmul(Bignum a, Bignum b, Bignum mod);
|
Bignum modmul(Bignum a, Bignum b, Bignum mod);
|
||||||
@ -238,6 +256,9 @@ Bignum biggcd(Bignum a, Bignum b);
|
|||||||
unsigned short bignum_mod_short(Bignum number, unsigned short modulus);
|
unsigned short bignum_mod_short(Bignum number, unsigned short modulus);
|
||||||
Bignum bignum_add_long(Bignum number, unsigned long addend);
|
Bignum bignum_add_long(Bignum number, unsigned long addend);
|
||||||
Bignum bigmul(Bignum a, Bignum b);
|
Bignum bigmul(Bignum a, Bignum b);
|
||||||
|
Bignum bigmuladd(Bignum a, Bignum b, Bignum addend);
|
||||||
|
Bignum bigdiv(Bignum a, Bignum b);
|
||||||
|
Bignum bigmod(Bignum a, Bignum b);
|
||||||
Bignum modinv(Bignum number, Bignum modulus);
|
Bignum modinv(Bignum number, Bignum modulus);
|
||||||
Bignum bignum_bitmask(Bignum number);
|
Bignum bignum_bitmask(Bignum number);
|
||||||
Bignum bignum_rshift(Bignum number, int shift);
|
Bignum bignum_rshift(Bignum number, int shift);
|
||||||
@ -280,12 +301,19 @@ void aes256_decrypt_pubkey(unsigned char *key, unsigned char *blk,
|
|||||||
/*
|
/*
|
||||||
* For progress updates in the key generation utility.
|
* For progress updates in the key generation utility.
|
||||||
*/
|
*/
|
||||||
typedef void (*progfn_t) (void *param, int phase, int progress);
|
#define PROGFN_LIN_PHASE 1
|
||||||
|
#define PROGFN_EXP_PHASE 2
|
||||||
|
#define PROGFN_PHASE_EXTENT 3
|
||||||
|
#define PROGFN_READY 4
|
||||||
|
#define PROGFN_PROGRESS 5
|
||||||
|
typedef void (*progfn_t) (void *param, int action, int phase, int progress);
|
||||||
|
|
||||||
int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn,
|
int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn,
|
||||||
void *pfnparam);
|
void *pfnparam);
|
||||||
Bignum primegen(int bits, int modulus, int residue, int phase,
|
int dsa_generate(struct dss_key *key, int bits, progfn_t pfn,
|
||||||
progfn_t pfn, void *pfnparam);
|
void *pfnparam);
|
||||||
|
Bignum primegen(int bits, int modulus, int residue, Bignum factor,
|
||||||
|
int phase, progfn_t pfn, void *pfnparam);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
58
sshbn.c
58
sshbn.c
@ -6,13 +6,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if 0 // use PuTTY main debugging for diagbn()
|
#include "misc.h"
|
||||||
#include <windows.h>
|
|
||||||
#include "putty.h"
|
|
||||||
#define debugprint debug
|
|
||||||
#else
|
|
||||||
#define debugprint(x) printf x
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BIGNUM_INTERNAL
|
#define BIGNUM_INTERNAL
|
||||||
typedef unsigned short *Bignum;
|
typedef unsigned short *Bignum;
|
||||||
@ -409,9 +403,10 @@ Bignum modmul(Bignum p, Bignum q, Bignum mod)
|
|||||||
* Compute p % mod.
|
* Compute p % mod.
|
||||||
* The most significant word of mod MUST be non-zero.
|
* The most significant word of mod MUST be non-zero.
|
||||||
* We assume that the result array is the same size as the mod array.
|
* We assume that the result array is the same size as the mod array.
|
||||||
* We optionally write out a quotient.
|
* We optionally write out a quotient if `quotient' is non-NULL.
|
||||||
|
* We can avoid writing out the result if `result' is NULL.
|
||||||
*/
|
*/
|
||||||
void bigmod(Bignum p, Bignum mod, Bignum result, Bignum quotient)
|
void bigdivmod(Bignum p, Bignum mod, Bignum result, Bignum quotient)
|
||||||
{
|
{
|
||||||
unsigned short *n, *m;
|
unsigned short *n, *m;
|
||||||
int mshift;
|
int mshift;
|
||||||
@ -460,10 +455,12 @@ void bigmod(Bignum p, Bignum mod, Bignum result, Bignum quotient)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Copy result to buffer */
|
/* Copy result to buffer */
|
||||||
|
if (result) {
|
||||||
for (i = 1; i <= result[0]; i++) {
|
for (i = 1; i <= result[0]; i++) {
|
||||||
int j = plen - i;
|
int j = plen - i;
|
||||||
result[i] = j >= 0 ? n[j] : 0;
|
result[i] = j >= 0 ? n[j] : 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Free temporary arrays */
|
/* Free temporary arrays */
|
||||||
for (i = 0; i < mlen; i++)
|
for (i = 0; i < mlen; i++)
|
||||||
@ -749,15 +746,16 @@ Bignum bignum_bitmask(Bignum n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert a (max 16-bit) short into a bignum.
|
* Convert a (max 32-bit) long into a bignum.
|
||||||
*/
|
*/
|
||||||
Bignum bignum_from_short(unsigned short n)
|
Bignum bignum_from_long(unsigned long n)
|
||||||
{
|
{
|
||||||
Bignum ret;
|
Bignum ret;
|
||||||
|
|
||||||
ret = newbn(2);
|
ret = newbn(3);
|
||||||
ret[1] = n & 0xFFFF;
|
ret[1] = n & 0xFFFF;
|
||||||
ret[2] = (n >> 16) & 0xFFFF;
|
ret[2] = (n >> 16) & 0xFFFF;
|
||||||
|
ret[3] = 0;
|
||||||
ret[0] = (ret[2] ? 2 : 1);
|
ret[0] = (ret[2] ? 2 : 1);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -804,21 +802,40 @@ void diagbn(char *prefix, Bignum md)
|
|||||||
int i, nibbles, morenibbles;
|
int i, nibbles, morenibbles;
|
||||||
static const char hex[] = "0123456789ABCDEF";
|
static const char hex[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
debugprint(("%s0x", prefix ? prefix : ""));
|
debug(("%s0x", prefix ? prefix : ""));
|
||||||
|
|
||||||
nibbles = (3 + bignum_bitcount(md)) / 4;
|
nibbles = (3 + bignum_bitcount(md)) / 4;
|
||||||
if (nibbles < 1)
|
if (nibbles < 1)
|
||||||
nibbles = 1;
|
nibbles = 1;
|
||||||
morenibbles = 4 * md[0] - nibbles;
|
morenibbles = 4 * md[0] - nibbles;
|
||||||
for (i = 0; i < morenibbles; i++)
|
for (i = 0; i < morenibbles; i++)
|
||||||
debugprint(("-"));
|
debug(("-"));
|
||||||
for (i = nibbles; i--;)
|
for (i = nibbles; i--;)
|
||||||
debugprint(
|
debug(("%c",
|
||||||
("%c",
|
|
||||||
hex[(bignum_byte(md, i / 2) >> (4 * (i % 2))) & 0xF]));
|
hex[(bignum_byte(md, i / 2) >> (4 * (i % 2))) & 0xF]));
|
||||||
|
|
||||||
if (prefix)
|
if (prefix)
|
||||||
debugprint(("\n"));
|
debug(("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple division.
|
||||||
|
*/
|
||||||
|
Bignum bigdiv(Bignum a, Bignum b)
|
||||||
|
{
|
||||||
|
Bignum q = newbn(a[0]);
|
||||||
|
bigdivmod(a, b, NULL, q);
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple remainder.
|
||||||
|
*/
|
||||||
|
Bignum bigmod(Bignum a, Bignum b)
|
||||||
|
{
|
||||||
|
Bignum r = newbn(b[0]);
|
||||||
|
bigdivmod(a, b, r, NULL);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -829,12 +846,9 @@ Bignum biggcd(Bignum av, Bignum bv)
|
|||||||
Bignum a = copybn(av);
|
Bignum a = copybn(av);
|
||||||
Bignum b = copybn(bv);
|
Bignum b = copybn(bv);
|
||||||
|
|
||||||
diagbn("a = ", a);
|
|
||||||
diagbn("b = ", b);
|
|
||||||
while (bignum_cmp(b, Zero) != 0) {
|
while (bignum_cmp(b, Zero) != 0) {
|
||||||
Bignum t = newbn(b[0]);
|
Bignum t = newbn(b[0]);
|
||||||
bigmod(a, b, t, NULL);
|
bigdivmod(a, b, t, NULL);
|
||||||
diagbn("t = ", t);
|
|
||||||
while (t[0] > 1 && t[t[0]] == 0)
|
while (t[0] > 1 && t[t[0]] == 0)
|
||||||
t[0]--;
|
t[0]--;
|
||||||
freebn(a);
|
freebn(a);
|
||||||
@ -860,7 +874,7 @@ Bignum modinv(Bignum number, Bignum modulus)
|
|||||||
while (bignum_cmp(b, One) != 0) {
|
while (bignum_cmp(b, One) != 0) {
|
||||||
Bignum t = newbn(b[0]);
|
Bignum t = newbn(b[0]);
|
||||||
Bignum q = newbn(a[0]);
|
Bignum q = newbn(a[0]);
|
||||||
bigmod(a, b, t, q);
|
bigdivmod(a, b, t, q);
|
||||||
while (t[0] > 1 && t[t[0]] == 0)
|
while (t[0] > 1 && t[t[0]] == 0)
|
||||||
t[0]--;
|
t[0]--;
|
||||||
freebn(a);
|
freebn(a);
|
||||||
|
317
sshdss.c
317
sshdss.c
@ -3,6 +3,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
#define GET_32BIT(cp) \
|
#define GET_32BIT(cp) \
|
||||||
(((unsigned long)(unsigned char)(cp)[0] << 24) | \
|
(((unsigned long)(unsigned char)(cp)[0] << 24) | \
|
||||||
@ -16,11 +17,35 @@
|
|||||||
(cp)[2] = (unsigned char)((value) >> 8); \
|
(cp)[2] = (unsigned char)((value) >> 8); \
|
||||||
(cp)[3] = (unsigned char)(value); }
|
(cp)[3] = (unsigned char)(value); }
|
||||||
|
|
||||||
#if 0
|
static void sha_mpint(SHA_State * s, Bignum b)
|
||||||
#define DEBUG_DSS
|
{
|
||||||
#else
|
unsigned char *p;
|
||||||
#define diagbn(x,y)
|
unsigned char lenbuf[4];
|
||||||
#endif
|
int len;
|
||||||
|
len = (bignum_bitcount(b) + 8) / 8;
|
||||||
|
PUT_32BIT(lenbuf, len);
|
||||||
|
SHA_Bytes(s, lenbuf, 4);
|
||||||
|
while (len-- > 0) {
|
||||||
|
lenbuf[0] = bignum_byte(b, len);
|
||||||
|
SHA_Bytes(s, lenbuf, 1);
|
||||||
|
}
|
||||||
|
memset(lenbuf, 0, sizeof(lenbuf));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sha512_mpint(SHA512_State * s, Bignum b)
|
||||||
|
{
|
||||||
|
unsigned char *p;
|
||||||
|
unsigned char lenbuf[4];
|
||||||
|
int len;
|
||||||
|
len = (bignum_bitcount(b) + 8) / 8;
|
||||||
|
PUT_32BIT(lenbuf, len);
|
||||||
|
SHA512_Bytes(s, lenbuf, 4);
|
||||||
|
while (len-- > 0) {
|
||||||
|
lenbuf[0] = bignum_byte(b, len);
|
||||||
|
SHA512_Bytes(s, lenbuf, 1);
|
||||||
|
}
|
||||||
|
memset(lenbuf, 0, sizeof(lenbuf));
|
||||||
|
}
|
||||||
|
|
||||||
static void getstring(char **data, int *datalen, char **p, int *length)
|
static void getstring(char **data, int *datalen, char **p, int *length)
|
||||||
{
|
{
|
||||||
@ -62,10 +87,6 @@ static Bignum get160(char **data, int *datalen)
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dss_key {
|
|
||||||
Bignum p, q, g, y;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void *dss_newkey(char *data, int len)
|
static void *dss_newkey(char *data, int len)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
@ -236,14 +257,8 @@ static int dss_verifysig(void *key, char *sig, int siglen,
|
|||||||
}
|
}
|
||||||
sig += 4, siglen -= 4; /* skip yet another length field */
|
sig += 4, siglen -= 4; /* skip yet another length field */
|
||||||
}
|
}
|
||||||
diagbn("p=", dss->p);
|
|
||||||
diagbn("q=", dss->q);
|
|
||||||
diagbn("g=", dss->g);
|
|
||||||
diagbn("y=", dss->y);
|
|
||||||
r = get160(&sig, &siglen);
|
r = get160(&sig, &siglen);
|
||||||
diagbn("r=", r);
|
|
||||||
s = get160(&sig, &siglen);
|
s = get160(&sig, &siglen);
|
||||||
diagbn("s=", s);
|
|
||||||
if (!r || !s)
|
if (!r || !s)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -251,7 +266,6 @@ static int dss_verifysig(void *key, char *sig, int siglen,
|
|||||||
* Step 1. w <- s^-1 mod q.
|
* Step 1. w <- s^-1 mod q.
|
||||||
*/
|
*/
|
||||||
w = modinv(s, dss->q);
|
w = modinv(s, dss->q);
|
||||||
diagbn("w=", w);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Step 2. u1 <- SHA(message) * w mod q.
|
* Step 2. u1 <- SHA(message) * w mod q.
|
||||||
@ -260,28 +274,20 @@ static int dss_verifysig(void *key, char *sig, int siglen,
|
|||||||
p = hash;
|
p = hash;
|
||||||
slen = 20;
|
slen = 20;
|
||||||
sha = get160(&p, &slen);
|
sha = get160(&p, &slen);
|
||||||
diagbn("sha=", sha);
|
|
||||||
u1 = modmul(sha, w, dss->q);
|
u1 = modmul(sha, w, dss->q);
|
||||||
diagbn("u1=", u1);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Step 3. u2 <- r * w mod q.
|
* Step 3. u2 <- r * w mod q.
|
||||||
*/
|
*/
|
||||||
u2 = modmul(r, w, dss->q);
|
u2 = modmul(r, w, dss->q);
|
||||||
diagbn("u2=", u2);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Step 4. v <- (g^u1 * y^u2 mod p) mod q.
|
* Step 4. v <- (g^u1 * y^u2 mod p) mod q.
|
||||||
*/
|
*/
|
||||||
gu1p = modpow(dss->g, u1, dss->p);
|
gu1p = modpow(dss->g, u1, dss->p);
|
||||||
diagbn("gu1p=", gu1p);
|
|
||||||
yu2p = modpow(dss->y, u2, dss->p);
|
yu2p = modpow(dss->y, u2, dss->p);
|
||||||
diagbn("yu2p=", yu2p);
|
|
||||||
gu1yu2p = modmul(gu1p, yu2p, dss->p);
|
gu1yu2p = modmul(gu1p, yu2p, dss->p);
|
||||||
diagbn("gu1yu2p=", gu1yu2p);
|
|
||||||
v = modmul(gu1yu2p, One, dss->q);
|
v = modmul(gu1yu2p, One, dss->q);
|
||||||
diagbn("gu1yu2q=v=", v);
|
|
||||||
diagbn("r=", r);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Step 5. v should now be equal to r.
|
* Step 5. v should now be equal to r.
|
||||||
@ -347,28 +353,281 @@ static unsigned char *dss_public_blob(void *key, int *len)
|
|||||||
|
|
||||||
static unsigned char *dss_private_blob(void *key, int *len)
|
static unsigned char *dss_private_blob(void *key, int *len)
|
||||||
{
|
{
|
||||||
return NULL; /* can't handle DSS private keys */
|
struct dss_key *dss = (struct dss_key *) key;
|
||||||
|
int xlen, bloblen;
|
||||||
|
int i;
|
||||||
|
unsigned char *blob, *p;
|
||||||
|
SHA_State s;
|
||||||
|
unsigned char digest[20];
|
||||||
|
|
||||||
|
xlen = (bignum_bitcount(dss->x) + 8) / 8;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mpint x, string[20] the SHA of p||q||g. Total 28 + xlen.
|
||||||
|
* (two length fields and twenty bytes, 20+8=28).
|
||||||
|
*/
|
||||||
|
bloblen = 28 + xlen;
|
||||||
|
blob = smalloc(bloblen);
|
||||||
|
p = blob;
|
||||||
|
PUT_32BIT(p, xlen);
|
||||||
|
p += 4;
|
||||||
|
for (i = xlen; i--;)
|
||||||
|
*p++ = bignum_byte(dss->x, i);
|
||||||
|
PUT_32BIT(p, 20);
|
||||||
|
SHA_Init(&s);
|
||||||
|
sha_mpint(&s, dss->p);
|
||||||
|
sha_mpint(&s, dss->q);
|
||||||
|
sha_mpint(&s, dss->g);
|
||||||
|
SHA_Final(&s, digest);
|
||||||
|
p += 4;
|
||||||
|
for (i = 0; i < 20; i++)
|
||||||
|
*p++ = digest[i];
|
||||||
|
assert(p == blob + bloblen);
|
||||||
|
*len = bloblen;
|
||||||
|
return blob;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *dss_createkey(unsigned char *pub_blob, int pub_len,
|
static void *dss_createkey(unsigned char *pub_blob, int pub_len,
|
||||||
unsigned char *priv_blob, int priv_len)
|
unsigned char *priv_blob, int priv_len)
|
||||||
{
|
{
|
||||||
return NULL; /* can't handle DSS private keys */
|
struct dss_key *dss;
|
||||||
|
char *pb = (char *) priv_blob;
|
||||||
|
char *hash;
|
||||||
|
int hashlen;
|
||||||
|
SHA_State s;
|
||||||
|
unsigned char digest[20];
|
||||||
|
Bignum ytest;
|
||||||
|
|
||||||
|
dss = dss_newkey((char *) pub_blob, pub_len);
|
||||||
|
dss->x = getmp(&pb, &priv_len);
|
||||||
|
getstring(&pb, &priv_len, &hash, &hashlen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify details of the key. First check that the hash is
|
||||||
|
* indeed a hash of p||q||g.
|
||||||
|
*/
|
||||||
|
if (hashlen != 20) {
|
||||||
|
dss_freekey(dss);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
SHA_Init(&s);
|
||||||
|
sha_mpint(&s, dss->p);
|
||||||
|
sha_mpint(&s, dss->q);
|
||||||
|
sha_mpint(&s, dss->g);
|
||||||
|
SHA_Final(&s, digest);
|
||||||
|
if (0 != memcmp(hash, digest, 20)) {
|
||||||
|
dss_freekey(dss);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now ensure g^x mod p really is y.
|
||||||
|
*/
|
||||||
|
ytest = modpow(dss->g, dss->x, dss->p);
|
||||||
|
if (0 != bignum_cmp(ytest, dss->y)) {
|
||||||
|
dss_freekey(dss);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
freebn(ytest);
|
||||||
|
|
||||||
|
return dss;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *dss_openssh_createkey(unsigned char **blob, int *len)
|
static void *dss_openssh_createkey(unsigned char **blob, int *len)
|
||||||
{
|
{
|
||||||
return NULL; /* can't handle DSS private keys */
|
char **b = (char **) blob;
|
||||||
|
struct dss_key *dss;
|
||||||
|
|
||||||
|
dss = smalloc(sizeof(struct dss_key));
|
||||||
|
if (!dss)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dss->p = getmp(b, len);
|
||||||
|
dss->q = getmp(b, len);
|
||||||
|
dss->g = getmp(b, len);
|
||||||
|
dss->y = getmp(b, len);
|
||||||
|
dss->x = getmp(b, len);
|
||||||
|
|
||||||
|
if (!dss->p || !dss->q || !dss->g || !dss->y || !dss->x) {
|
||||||
|
sfree(dss->p);
|
||||||
|
sfree(dss->q);
|
||||||
|
sfree(dss->g);
|
||||||
|
sfree(dss->y);
|
||||||
|
sfree(dss->x);
|
||||||
|
sfree(dss);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dss;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dss_openssh_fmtkey(void *key, unsigned char *blob, int len)
|
static int dss_openssh_fmtkey(void *key, unsigned char *blob, int len)
|
||||||
{
|
{
|
||||||
return -1; /* can't handle DSS private keys */
|
struct dss_key *dss = (struct dss_key *) key;
|
||||||
|
int bloblen, i;
|
||||||
|
|
||||||
|
bloblen =
|
||||||
|
ssh2_bignum_length(dss->p) +
|
||||||
|
ssh2_bignum_length(dss->q) +
|
||||||
|
ssh2_bignum_length(dss->g) +
|
||||||
|
ssh2_bignum_length(dss->y) +
|
||||||
|
ssh2_bignum_length(dss->x);
|
||||||
|
|
||||||
|
if (bloblen > len)
|
||||||
|
return bloblen;
|
||||||
|
|
||||||
|
bloblen = 0;
|
||||||
|
#define ENC(x) \
|
||||||
|
PUT_32BIT(blob+bloblen, ssh2_bignum_length((x))-4); bloblen += 4; \
|
||||||
|
for (i = ssh2_bignum_length((x))-4; i-- ;) blob[bloblen++]=bignum_byte((x),i);
|
||||||
|
ENC(dss->p);
|
||||||
|
ENC(dss->q);
|
||||||
|
ENC(dss->g);
|
||||||
|
ENC(dss->y);
|
||||||
|
ENC(dss->x);
|
||||||
|
|
||||||
|
return bloblen;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen)
|
unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen)
|
||||||
{
|
{
|
||||||
return NULL; /* can't handle DSS private keys */
|
/*
|
||||||
|
* The basic DSS signing algorithm is:
|
||||||
|
*
|
||||||
|
* - invent a random k between 1 and q-1 (exclusive).
|
||||||
|
* - Compute r = (g^k mod p) mod q.
|
||||||
|
* - Compute s = k^-1 * (hash + x*r) mod q.
|
||||||
|
*
|
||||||
|
* This has the dangerous properties that:
|
||||||
|
*
|
||||||
|
* - if an attacker in possession of the public key _and_ the
|
||||||
|
* signature (for example, the host you just authenticated
|
||||||
|
* to) can guess your k, he can reverse the computation of s
|
||||||
|
* and work out x = r^-1 * (s*k - hash) mod q. That is, he
|
||||||
|
* can deduce the private half of your key, and masquerade
|
||||||
|
* as you for as long as the key is still valid.
|
||||||
|
*
|
||||||
|
* - since r is a function purely of k and the public key, if
|
||||||
|
* the attacker only has a _range of possibilities_ for k
|
||||||
|
* it's easy for him to work through them all and check each
|
||||||
|
* one against r; he'll never be unsure of whether he's got
|
||||||
|
* the right one.
|
||||||
|
*
|
||||||
|
* - if you ever sign two different hashes with the same k, it
|
||||||
|
* will be immediately obvious because the two signatures
|
||||||
|
* will have the same r, and moreover an attacker in
|
||||||
|
* possession of both signatures (and the public key of
|
||||||
|
* course) can compute k = (hash1-hash2) * (s1-s2)^-1 mod q,
|
||||||
|
* and from there deduce x as before.
|
||||||
|
*
|
||||||
|
* - the Bleichenbacher attack on DSA makes use of methods of
|
||||||
|
* generating k which are significantly non-uniformly
|
||||||
|
* distributed; in particular, generating a 160-bit random
|
||||||
|
* number and reducing it mod q is right out.
|
||||||
|
*
|
||||||
|
* For this reason we must be pretty careful about how we
|
||||||
|
* generate our k. Since this code runs on Windows, with no
|
||||||
|
* particularly good system entropy sources, we can't trust our
|
||||||
|
* RNG itself to produce properly unpredictable data. Hence, we
|
||||||
|
* use a totally different scheme instead.
|
||||||
|
*
|
||||||
|
* What we do is to take a SHA-512 (_big_) hash of the private
|
||||||
|
* key x, and then feed this into another SHA-512 hash that
|
||||||
|
* also includes the message hash being signed. That is:
|
||||||
|
*
|
||||||
|
* proto_k = SHA512 ( SHA512(x) || SHA160(message) )
|
||||||
|
*
|
||||||
|
* This number is 512 bits long, so reducing it mod q won't be
|
||||||
|
* noticeably non-uniform. So
|
||||||
|
*
|
||||||
|
* k = proto_k mod q
|
||||||
|
*
|
||||||
|
* This has the interesting property that it's _deterministic_:
|
||||||
|
* signing the same hash twice with the same key yields the
|
||||||
|
* same signature.
|
||||||
|
*
|
||||||
|
* (It doesn't, _per se_, protect against reuse of k. Reuse of
|
||||||
|
* k is left to chance; all it does is prevent _excessively
|
||||||
|
* high_ chances of reuse of k due to entropy problems.)
|
||||||
|
*
|
||||||
|
* Thanks to Colin Plumb for the general idea of using x to
|
||||||
|
* ensure k is hard to guess, and to the Cambridge University
|
||||||
|
* Computer Security Group for helping to argue out all the
|
||||||
|
* fine details.
|
||||||
|
*/
|
||||||
|
struct dss_key *dss = (struct dss_key *) key;
|
||||||
|
SHA512_State ss;
|
||||||
|
unsigned char digest[20], digest512[64];
|
||||||
|
Bignum proto_k, k, gkp, hash, kinv, hxr, r, s;
|
||||||
|
unsigned char *bytes;
|
||||||
|
int nbytes, i;
|
||||||
|
|
||||||
|
SHA_Simple(data, datalen, digest);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hash some identifying text plus x.
|
||||||
|
*/
|
||||||
|
SHA512_Init(&ss);
|
||||||
|
SHA512_Bytes(&ss, "DSA deterministic k generator", 30);
|
||||||
|
sha512_mpint(&ss, dss->x);
|
||||||
|
SHA512_Final(&ss, digest512);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now hash that digest plus the message hash.
|
||||||
|
*/
|
||||||
|
SHA512_Init(&ss);
|
||||||
|
SHA512_Bytes(&ss, digest512, sizeof(digest512));
|
||||||
|
SHA512_Bytes(&ss, digest, sizeof(digest));
|
||||||
|
SHA512_Final(&ss, digest512);
|
||||||
|
|
||||||
|
memset(&ss, 0, sizeof(ss));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now convert the result into a bignum, and reduce it mod q.
|
||||||
|
*/
|
||||||
|
proto_k = bignum_from_bytes(digest512, 64);
|
||||||
|
k = bigmod(proto_k, dss->q);
|
||||||
|
freebn(proto_k);
|
||||||
|
|
||||||
|
memset(digest512, 0, sizeof(digest512));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we have k, so just go ahead and compute the signature.
|
||||||
|
*/
|
||||||
|
gkp = modpow(dss->g, k, dss->p); /* g^k mod p */
|
||||||
|
r = bigmod(gkp, dss->q); /* r = (g^k mod p) mod q */
|
||||||
|
freebn(gkp);
|
||||||
|
|
||||||
|
hash = bignum_from_bytes(digest, 20);
|
||||||
|
kinv = modinv(k, dss->q); /* k^-1 mod q */
|
||||||
|
hxr = bigmuladd(dss->x, r, hash); /* hash + x*r */
|
||||||
|
s = modmul(kinv, hxr, dss->q); /* s = k^-1 * (hash + x*r) mod q */
|
||||||
|
freebn(hxr);
|
||||||
|
freebn(kinv);
|
||||||
|
freebn(hash);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Signature blob is
|
||||||
|
*
|
||||||
|
* string "ssh-dss"
|
||||||
|
* string two 20-byte numbers r and s, end to end
|
||||||
|
*
|
||||||
|
* i.e. 4+7 + 4+40 bytes.
|
||||||
|
*/
|
||||||
|
nbytes = 4 + 7 + 4 + 40;
|
||||||
|
bytes = smalloc(nbytes);
|
||||||
|
PUT_32BIT(bytes, 7);
|
||||||
|
memcpy(bytes + 4, "ssh-dss", 7);
|
||||||
|
PUT_32BIT(bytes + 4 + 7, 40);
|
||||||
|
for (i = 0; i < 20; i++) {
|
||||||
|
bytes[4 + 7 + 4 + i] = bignum_byte(r, 19 - i);
|
||||||
|
bytes[4 + 7 + 4 + 20 + i] = bignum_byte(s, 19 - i);
|
||||||
|
}
|
||||||
|
freebn(r);
|
||||||
|
freebn(s);
|
||||||
|
|
||||||
|
*siglen = nbytes;
|
||||||
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct ssh_signkey ssh_dss = {
|
const struct ssh_signkey ssh_dss = {
|
||||||
|
54
sshprime.c
54
sshprime.c
@ -2,6 +2,7 @@
|
|||||||
* Prime generation.
|
* Prime generation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1182,14 +1183,25 @@ static const unsigned short primes[] = {
|
|||||||
#define NPRIMES (sizeof(primes) / sizeof(*primes))
|
#define NPRIMES (sizeof(primes) / sizeof(*primes))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate a prime. We arrange to select a prime with the property
|
* Generate a prime. We can deal with various extra properties of
|
||||||
* (prime % modulus) != residue (to speed up use in RSA).
|
* the prime:
|
||||||
|
*
|
||||||
|
* - to speed up use in RSA, we can arrange to select a prime with
|
||||||
|
* the property (prime % modulus) != residue.
|
||||||
|
*
|
||||||
|
* - for use in DSA, we can arrange to select a prime which is one
|
||||||
|
* more than a multiple of a dirty great bignum. In this case
|
||||||
|
* `bits' gives the size of the factor by which we _multiply_
|
||||||
|
* that bignum, rather than the size of the whole number.
|
||||||
*/
|
*/
|
||||||
Bignum primegen(int bits, int modulus, int residue,
|
Bignum primegen(int bits, int modulus, int residue, Bignum factor,
|
||||||
int phase, progfn_t pfn, void *pfnparam)
|
int phase, progfn_t pfn, void *pfnparam)
|
||||||
{
|
{
|
||||||
int i, k, v, byte, bitsleft, check, checks;
|
int i, k, v, byte, bitsleft, check, checks;
|
||||||
unsigned long delta, moduli[NPRIMES + 1], residues[NPRIMES + 1];
|
unsigned long delta;
|
||||||
|
unsigned long moduli[NPRIMES + 1];
|
||||||
|
unsigned long residues[NPRIMES + 1];
|
||||||
|
unsigned long multipliers[NPRIMES + 1];
|
||||||
Bignum p, pm1, q, wqp, wqp2;
|
Bignum p, pm1, q, wqp, wqp2;
|
||||||
int progress = 0;
|
int progress = 0;
|
||||||
|
|
||||||
@ -1198,15 +1210,18 @@ Bignum primegen(int bits, int modulus, int residue,
|
|||||||
|
|
||||||
STARTOVER:
|
STARTOVER:
|
||||||
|
|
||||||
pfn(pfnparam, phase, ++progress);
|
pfn(pfnparam, PROGFN_PROGRESS, phase, ++progress);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate a k-bit random number with top and bottom bits set.
|
* Generate a k-bit random number with top and bottom bits set.
|
||||||
|
* Alternatively, if `factor' is nonzero, generate a k-bit
|
||||||
|
* random number with the top bit set and the bottom bit clear,
|
||||||
|
* multiply it by `factor', and add one.
|
||||||
*/
|
*/
|
||||||
p = bn_power_2(bits - 1);
|
p = bn_power_2(bits - 1);
|
||||||
for (i = 0; i < bits; i++) {
|
for (i = 0; i < bits; i++) {
|
||||||
if (i == 0 || i == bits - 1)
|
if (i == 0 || i == bits - 1)
|
||||||
v = 1;
|
v = (i != 0 || !factor) ? 1 : 0;
|
||||||
else {
|
else {
|
||||||
if (bitsleft <= 0)
|
if (bitsleft <= 0)
|
||||||
bitsleft = 8, byte = random_byte();
|
bitsleft = 8, byte = random_byte();
|
||||||
@ -1216,14 +1231,26 @@ Bignum primegen(int bits, int modulus, int residue,
|
|||||||
}
|
}
|
||||||
bignum_set_bit(p, i, v);
|
bignum_set_bit(p, i, v);
|
||||||
}
|
}
|
||||||
|
if (factor) {
|
||||||
|
Bignum tmp = p;
|
||||||
|
p = bigmul(tmp, factor);
|
||||||
|
freebn(tmp);
|
||||||
|
assert(bignum_bit(p, 0) == 0);
|
||||||
|
bignum_set_bit(p, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure this random number is coprime to the first few
|
* Ensure this random number is coprime to the first few
|
||||||
* primes, by repeatedly adding 2 to it until it is.
|
* primes, by repeatedly adding either 2 or 2*factor to it
|
||||||
|
* until it is.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < NPRIMES; i++) {
|
for (i = 0; i < NPRIMES; i++) {
|
||||||
moduli[i] = primes[i];
|
moduli[i] = primes[i];
|
||||||
residues[i] = bignum_mod_short(p, primes[i]);
|
residues[i] = bignum_mod_short(p, primes[i]);
|
||||||
|
if (factor)
|
||||||
|
multipliers[i] = bignum_mod_short(factor, primes[i]);
|
||||||
|
else
|
||||||
|
multipliers[i] = 1;
|
||||||
}
|
}
|
||||||
moduli[NPRIMES] = modulus;
|
moduli[NPRIMES] = modulus;
|
||||||
residues[NPRIMES] = (bignum_mod_short(p, (unsigned short) modulus)
|
residues[NPRIMES] = (bignum_mod_short(p, (unsigned short) modulus)
|
||||||
@ -1231,11 +1258,11 @@ Bignum primegen(int bits, int modulus, int residue,
|
|||||||
delta = 0;
|
delta = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
for (i = 0; i < (sizeof(moduli) / sizeof(*moduli)); i++)
|
for (i = 0; i < (sizeof(moduli) / sizeof(*moduli)); i++)
|
||||||
if (!((residues[i] + delta) % moduli[i]))
|
if (!((residues[i] + delta * multipliers[i]) % moduli[i]))
|
||||||
break;
|
break;
|
||||||
if (i < (sizeof(moduli) / sizeof(*moduli))) { /* we broke */
|
if (i < (sizeof(moduli) / sizeof(*moduli))) { /* we broke */
|
||||||
delta += 2;
|
delta += 2;
|
||||||
if (delta < 2) {
|
if (delta > 65536) {
|
||||||
freebn(p);
|
freebn(p);
|
||||||
goto STARTOVER;
|
goto STARTOVER;
|
||||||
}
|
}
|
||||||
@ -1244,7 +1271,14 @@ Bignum primegen(int bits, int modulus, int residue,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
q = p;
|
q = p;
|
||||||
|
if (factor) {
|
||||||
|
Bignum tmp;
|
||||||
|
tmp = bignum_from_long(delta);
|
||||||
|
p = bigmuladd(tmp, factor, q);
|
||||||
|
freebn(tmp);
|
||||||
|
} else {
|
||||||
p = bignum_add_long(q, delta);
|
p = bignum_add_long(q, delta);
|
||||||
|
}
|
||||||
freebn(q);
|
freebn(q);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1311,7 +1345,7 @@ Bignum primegen(int bits, int modulus, int residue,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pfn(pfnparam, phase, ++progress);
|
pfn(pfnparam, PROGFN_PROGRESS, phase, ++progress);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute w^q mod p.
|
* Compute w^q mod p.
|
||||||
|
149
sshpubk.c
149
sshpubk.c
@ -307,8 +307,7 @@ int saversakey(char *filename, struct RSAKey *key, char *passphrase)
|
|||||||
* and LF-only are tolerated on input.
|
* and LF-only are tolerated on input.
|
||||||
*
|
*
|
||||||
* The first line says "PuTTY-User-Key-File-1: " plus the name of the
|
* The first line says "PuTTY-User-Key-File-1: " plus the name of the
|
||||||
* algorithm ("ssh-dss", "ssh-rsa" etc. Although, of course, this
|
* algorithm ("ssh-dss", "ssh-rsa" etc).
|
||||||
* being PuTTY, "ssh-dss" is not supported.)
|
|
||||||
*
|
*
|
||||||
* The next line says "Encryption: " plus an encryption type.
|
* The next line says "Encryption: " plus an encryption type.
|
||||||
* Currently the only supported encryption types are "aes256-cbc"
|
* Currently the only supported encryption types are "aes256-cbc"
|
||||||
@ -337,16 +336,37 @@ int saversakey(char *filename, struct RSAKey *key, char *passphrase)
|
|||||||
* mpint iqmp (the inverse of q modulo p)
|
* mpint iqmp (the inverse of q modulo p)
|
||||||
* data padding (to reach a multiple of the cipher block size)
|
* data padding (to reach a multiple of the cipher block size)
|
||||||
*
|
*
|
||||||
* Finally, there is a line saying "Private-Hash: " plus a hex
|
* And for "ssh-dss", it will be composed of
|
||||||
* representation of a SHA-1 hash of the plaintext version of the
|
*
|
||||||
* private part, including the final padding.
|
* mpint x (the private key parameter)
|
||||||
|
* string hash (20-byte hash of mpints p || q || g)
|
||||||
|
*
|
||||||
|
* Finally, there is a line saying _either_
|
||||||
|
*
|
||||||
|
* - "Private-Hash: " plus a hex representation of a SHA-1 hash of
|
||||||
|
* the plaintext version of the private part, including the
|
||||||
|
* final padding.
|
||||||
|
*
|
||||||
|
* or
|
||||||
|
*
|
||||||
|
* - "Private-MAC: " plus a hex representation of a HMAC-SHA-1 of
|
||||||
|
* the plaintext version of the private part, including the
|
||||||
|
* final padding.
|
||||||
|
*
|
||||||
|
* The key to the MAC is itself a SHA-1 hash of:
|
||||||
|
*
|
||||||
|
* data "putty-private-key-file-mac-key"
|
||||||
|
* data passphrase
|
||||||
|
*
|
||||||
|
* Encrypted keys should have a MAC, whereas unencrypted ones must
|
||||||
|
* have a hash.
|
||||||
*
|
*
|
||||||
* If the key is encrypted, the encryption key is derived from the
|
* If the key is encrypted, the encryption key is derived from the
|
||||||
* passphrase by means of a succession of SHA-1 hashes. Each hash
|
* passphrase by means of a succession of SHA-1 hashes. Each hash
|
||||||
* is the hash of:
|
* is the hash of:
|
||||||
*
|
*
|
||||||
* uint32 sequence-number
|
* uint32 sequence-number
|
||||||
* string passphrase
|
* data passphrase
|
||||||
*
|
*
|
||||||
* where the sequence-number increases from zero. As many of these
|
* where the sequence-number increases from zero. As many of these
|
||||||
* hashes are used as necessary.
|
* hashes are used as necessary.
|
||||||
@ -357,9 +377,10 @@ int saversakey(char *filename, struct RSAKey *key, char *passphrase)
|
|||||||
* intact.
|
* intact.
|
||||||
*
|
*
|
||||||
* With RSA, this is easy: verify that n = p*q, and also verify
|
* With RSA, this is easy: verify that n = p*q, and also verify
|
||||||
* that e*d == 1 modulo (p-1)(q-1). With DSA (if we were ever to
|
* that e*d == 1 modulo (p-1)(q-1). With DSA, we need to store
|
||||||
* support it), we would need to store extra data in the private
|
* extra data in the private section other than just x, namely a
|
||||||
* section other than just x.
|
* hash of p||q||g. (It's then easy to verify that y is equal to
|
||||||
|
* g^x mod p.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int read_header(FILE * fp, char *header)
|
static int read_header(FILE * fp, char *header)
|
||||||
@ -514,16 +535,17 @@ struct ssh2_userkey ssh2_wrong_passphrase = {
|
|||||||
struct ssh2_userkey *ssh2_load_userkey(char *filename, char *passphrase)
|
struct ssh2_userkey *ssh2_load_userkey(char *filename, char *passphrase)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char header[40], *b, *comment, *hash;
|
char header[40], *b, *comment, *mac;
|
||||||
const struct ssh_signkey *alg;
|
const struct ssh_signkey *alg;
|
||||||
struct ssh2_userkey *ret;
|
struct ssh2_userkey *ret;
|
||||||
int cipher, cipherblk;
|
int cipher, cipherblk;
|
||||||
unsigned char *public_blob, *private_blob;
|
unsigned char *public_blob, *private_blob;
|
||||||
int public_blob_len, private_blob_len;
|
int public_blob_len, private_blob_len;
|
||||||
int i;
|
int i, is_mac;
|
||||||
|
int passlen = passphrase ? strlen(passphrase) : 0;
|
||||||
|
|
||||||
ret = NULL; /* return NULL for most errors */
|
ret = NULL; /* return NULL for most errors */
|
||||||
comment = hash = NULL;
|
comment = mac = NULL;
|
||||||
public_blob = private_blob = NULL;
|
public_blob = private_blob = NULL;
|
||||||
|
|
||||||
fp = fopen(filename, "rb");
|
fp = fopen(filename, "rb");
|
||||||
@ -536,9 +558,11 @@ struct ssh2_userkey *ssh2_load_userkey(char *filename, char *passphrase)
|
|||||||
goto error;
|
goto error;
|
||||||
if ((b = read_body(fp)) == NULL)
|
if ((b = read_body(fp)) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
/* Select key algorithm structure. Currently only ssh-rsa. */
|
/* Select key algorithm structure. */
|
||||||
if (!strcmp(b, "ssh-rsa"))
|
if (!strcmp(b, "ssh-rsa"))
|
||||||
alg = &ssh_rsa;
|
alg = &ssh_rsa;
|
||||||
|
else if (!strcmp(b, "ssh-dss"))
|
||||||
|
alg = &ssh_dss;
|
||||||
else {
|
else {
|
||||||
sfree(b);
|
sfree(b);
|
||||||
goto error;
|
goto error;
|
||||||
@ -588,10 +612,18 @@ struct ssh2_userkey *ssh2_load_userkey(char *filename, char *passphrase)
|
|||||||
if ((private_blob = read_blob(fp, i, &private_blob_len)) == NULL)
|
if ((private_blob = read_blob(fp, i, &private_blob_len)) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* Read the Private-Hash header line. */
|
/* Read the Private-MAC or Private-Hash header line. */
|
||||||
if (!read_header(fp, header) || 0 != strcmp(header, "Private-Hash"))
|
if (!read_header(fp, header))
|
||||||
goto error;
|
goto error;
|
||||||
if ((hash = read_body(fp)) == NULL)
|
if (0 == strcmp(header, "Private-MAC")) {
|
||||||
|
if ((mac = read_body(fp)) == NULL)
|
||||||
|
goto error;
|
||||||
|
is_mac = 1;
|
||||||
|
} else if (0 == strcmp(header, "Private-Hash")) {
|
||||||
|
if ((mac = read_body(fp)) == NULL)
|
||||||
|
goto error;
|
||||||
|
is_mac = 0;
|
||||||
|
} else
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@ -603,15 +635,12 @@ struct ssh2_userkey *ssh2_load_userkey(char *filename, char *passphrase)
|
|||||||
if (cipher) {
|
if (cipher) {
|
||||||
unsigned char key[40];
|
unsigned char key[40];
|
||||||
SHA_State s;
|
SHA_State s;
|
||||||
int passlen;
|
|
||||||
|
|
||||||
if (!passphrase)
|
if (!passphrase)
|
||||||
goto error;
|
goto error;
|
||||||
if (private_blob_len % cipherblk)
|
if (private_blob_len % cipherblk)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
passlen = strlen(passphrase);
|
|
||||||
|
|
||||||
SHA_Init(&s);
|
SHA_Init(&s);
|
||||||
SHA_Bytes(&s, "\0\0\0\0", 4);
|
SHA_Bytes(&s, "\0\0\0\0", 4);
|
||||||
SHA_Bytes(&s, passphrase, passlen);
|
SHA_Bytes(&s, passphrase, passlen);
|
||||||
@ -627,21 +656,41 @@ struct ssh2_userkey *ssh2_load_userkey(char *filename, char *passphrase)
|
|||||||
* Verify the private hash.
|
* Verify the private hash.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
char realhash[41];
|
char realmac[41];
|
||||||
unsigned char binary[20];
|
unsigned char binary[20];
|
||||||
|
|
||||||
SHA_Simple(private_blob, private_blob_len, binary);
|
if (is_mac) {
|
||||||
for (i = 0; i < 20; i++)
|
SHA_State s;
|
||||||
sprintf(realhash + 2 * i, "%02x", binary[i]);
|
unsigned char mackey[20];
|
||||||
|
char header[] = "putty-private-key-file-mac-key";
|
||||||
|
|
||||||
if (strcmp(hash, realhash)) {
|
if (!passphrase) /* can't have MAC in unencrypted key */
|
||||||
/* An incorrect hash is an unconditional Error if the key is
|
goto error;
|
||||||
|
|
||||||
|
SHA_Init(&s);
|
||||||
|
SHA_Bytes(&s, header, sizeof(header)-1);
|
||||||
|
SHA_Bytes(&s, passphrase, passlen);
|
||||||
|
SHA_Final(&s, mackey);
|
||||||
|
|
||||||
|
hmac_sha1_simple(mackey, 20, private_blob, private_blob_len,
|
||||||
|
binary);
|
||||||
|
|
||||||
|
memset(mackey, 0, sizeof(mackey));
|
||||||
|
memset(&s, 0, sizeof(s));
|
||||||
|
} else {
|
||||||
|
SHA_Simple(private_blob, private_blob_len, binary);
|
||||||
|
}
|
||||||
|
for (i = 0; i < 20; i++)
|
||||||
|
sprintf(realmac + 2 * i, "%02x", binary[i]);
|
||||||
|
|
||||||
|
if (strcmp(mac, realmac)) {
|
||||||
|
/* An incorrect MAC is an unconditional Error if the key is
|
||||||
* unencrypted. Otherwise, it means Wrong Passphrase. */
|
* unencrypted. Otherwise, it means Wrong Passphrase. */
|
||||||
ret = cipher ? SSH2_WRONG_PASSPHRASE : NULL;
|
ret = cipher ? SSH2_WRONG_PASSPHRASE : NULL;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sfree(hash);
|
sfree(mac);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create and return the key.
|
* Create and return the key.
|
||||||
@ -668,8 +717,8 @@ struct ssh2_userkey *ssh2_load_userkey(char *filename, char *passphrase)
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
if (comment)
|
if (comment)
|
||||||
sfree(comment);
|
sfree(comment);
|
||||||
if (hash)
|
if (mac)
|
||||||
sfree(hash);
|
sfree(mac);
|
||||||
if (public_blob)
|
if (public_blob)
|
||||||
sfree(public_blob);
|
sfree(public_blob);
|
||||||
if (private_blob)
|
if (private_blob)
|
||||||
@ -702,6 +751,8 @@ char *ssh2_userkey_loadpub(char *filename, char **algorithm,
|
|||||||
/* Select key algorithm structure. Currently only ssh-rsa. */
|
/* Select key algorithm structure. Currently only ssh-rsa. */
|
||||||
if (!strcmp(b, "ssh-rsa"))
|
if (!strcmp(b, "ssh-rsa"))
|
||||||
alg = &ssh_rsa;
|
alg = &ssh_rsa;
|
||||||
|
else if (!strcmp(b, "ssh-dss"))
|
||||||
|
alg = &ssh_dss;
|
||||||
else {
|
else {
|
||||||
sfree(b);
|
sfree(b);
|
||||||
goto error;
|
goto error;
|
||||||
@ -863,9 +914,9 @@ int ssh2_save_userkey(char *filename, struct ssh2_userkey *key,
|
|||||||
int pub_blob_len, priv_blob_len, priv_encrypted_len;
|
int pub_blob_len, priv_blob_len, priv_encrypted_len;
|
||||||
int passlen;
|
int passlen;
|
||||||
int cipherblk;
|
int cipherblk;
|
||||||
int i;
|
int i, is_mac;
|
||||||
char *cipherstr;
|
char *cipherstr;
|
||||||
unsigned char priv_hash[20];
|
unsigned char priv_mac[20];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fetch the key component blobs.
|
* Fetch the key component blobs.
|
||||||
@ -895,13 +946,35 @@ int ssh2_save_userkey(char *filename, struct ssh2_userkey *key,
|
|||||||
memcpy(priv_blob_encrypted, priv_blob, priv_blob_len);
|
memcpy(priv_blob_encrypted, priv_blob, priv_blob_len);
|
||||||
/* Create padding based on the SHA hash of the unpadded blob. This prevents
|
/* Create padding based on the SHA hash of the unpadded blob. This prevents
|
||||||
* too easy a known-plaintext attack on the last block. */
|
* too easy a known-plaintext attack on the last block. */
|
||||||
SHA_Simple(priv_blob, priv_blob_len, priv_hash);
|
SHA_Simple(priv_blob, priv_blob_len, priv_mac);
|
||||||
assert(priv_encrypted_len - priv_blob_len < 20);
|
assert(priv_encrypted_len - priv_blob_len < 20);
|
||||||
memcpy(priv_blob_encrypted + priv_blob_len, priv_hash,
|
memcpy(priv_blob_encrypted + priv_blob_len, priv_mac,
|
||||||
priv_encrypted_len - priv_blob_len);
|
priv_encrypted_len - priv_blob_len);
|
||||||
|
|
||||||
/* Now create the _real_ private hash. */
|
/* Now create the private MAC. */
|
||||||
SHA_Simple(priv_blob_encrypted, priv_encrypted_len, priv_hash);
|
if (passphrase) {
|
||||||
|
SHA_State s;
|
||||||
|
unsigned char mackey[20];
|
||||||
|
char header[] = "putty-private-key-file-mac-key";
|
||||||
|
|
||||||
|
passlen = strlen(passphrase);
|
||||||
|
|
||||||
|
SHA_Init(&s);
|
||||||
|
SHA_Bytes(&s, header, sizeof(header)-1);
|
||||||
|
SHA_Bytes(&s, passphrase, passlen);
|
||||||
|
SHA_Final(&s, mackey);
|
||||||
|
|
||||||
|
hmac_sha1_simple(mackey, 20,
|
||||||
|
priv_blob_encrypted, priv_encrypted_len,
|
||||||
|
priv_mac);
|
||||||
|
is_mac = 1;
|
||||||
|
|
||||||
|
memset(mackey, 0, sizeof(mackey));
|
||||||
|
memset(&s, 0, sizeof(s));
|
||||||
|
} else {
|
||||||
|
SHA_Simple(priv_blob_encrypted, priv_encrypted_len, priv_mac);
|
||||||
|
is_mac = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (passphrase) {
|
if (passphrase) {
|
||||||
char key[40];
|
char key[40];
|
||||||
@ -919,6 +992,9 @@ int ssh2_save_userkey(char *filename, struct ssh2_userkey *key,
|
|||||||
SHA_Final(&s, key + 20);
|
SHA_Final(&s, key + 20);
|
||||||
aes256_encrypt_pubkey(key, priv_blob_encrypted,
|
aes256_encrypt_pubkey(key, priv_blob_encrypted,
|
||||||
priv_encrypted_len);
|
priv_encrypted_len);
|
||||||
|
|
||||||
|
memset(key, 0, sizeof(key));
|
||||||
|
memset(&s, 0, sizeof(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = fopen(filename, "w");
|
fp = fopen(filename, "w");
|
||||||
@ -931,9 +1007,12 @@ int ssh2_save_userkey(char *filename, struct ssh2_userkey *key,
|
|||||||
base64_encode(fp, pub_blob, pub_blob_len);
|
base64_encode(fp, pub_blob, pub_blob_len);
|
||||||
fprintf(fp, "Private-Lines: %d\n", base64_lines(priv_encrypted_len));
|
fprintf(fp, "Private-Lines: %d\n", base64_lines(priv_encrypted_len));
|
||||||
base64_encode(fp, priv_blob_encrypted, priv_encrypted_len);
|
base64_encode(fp, priv_blob_encrypted, priv_encrypted_len);
|
||||||
|
if (is_mac)
|
||||||
|
fprintf(fp, "Private-MAC: ");
|
||||||
|
else
|
||||||
fprintf(fp, "Private-Hash: ");
|
fprintf(fp, "Private-Hash: ");
|
||||||
for (i = 0; i < 20; i++)
|
for (i = 0; i < 20; i++)
|
||||||
fprintf(fp, "%02x", priv_hash[i]);
|
fprintf(fp, "%02x", priv_mac[i]);
|
||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return 1;
|
return 1;
|
||||||
|
50
sshrsag.c
50
sshrsag.c
@ -6,28 +6,6 @@
|
|||||||
|
|
||||||
#define RSA_EXPONENT 37 /* we like this prime */
|
#define RSA_EXPONENT 37 /* we like this prime */
|
||||||
|
|
||||||
#if 0 /* bignum diagnostic function */
|
|
||||||
static void diagbn(char *prefix, Bignum md)
|
|
||||||
{
|
|
||||||
int i, nibbles, morenibbles;
|
|
||||||
static const char hex[] = "0123456789ABCDEF";
|
|
||||||
|
|
||||||
printf("%s0x", prefix ? prefix : "");
|
|
||||||
|
|
||||||
nibbles = (3 + bignum_bitcount(md)) / 4;
|
|
||||||
if (nibbles < 1)
|
|
||||||
nibbles = 1;
|
|
||||||
morenibbles = 4 * md[0] - nibbles;
|
|
||||||
for (i = 0; i < morenibbles; i++)
|
|
||||||
putchar('-');
|
|
||||||
for (i = nibbles; i--;)
|
|
||||||
putchar(hex[(bignum_byte(md, i / 2) >> (4 * (i % 2))) & 0xF]);
|
|
||||||
|
|
||||||
if (prefix)
|
|
||||||
putchar('\n');
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn,
|
int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn,
|
||||||
void *pfnparam)
|
void *pfnparam)
|
||||||
{
|
{
|
||||||
@ -61,14 +39,18 @@ int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn,
|
|||||||
* time. We do this in 16-bit fixed point, so 29.34 becomes
|
* time. We do this in 16-bit fixed point, so 29.34 becomes
|
||||||
* 0x1D.57C4.
|
* 0x1D.57C4.
|
||||||
*/
|
*/
|
||||||
pfn(pfnparam, -1, -0x1D57C4 / (bits / 2));
|
pfn(pfnparam, PROGFN_PHASE_EXTENT, 1, 0x10000);
|
||||||
pfn(pfnparam, -2, -0x1D57C4 / (bits - bits / 2));
|
pfn(pfnparam, PROGFN_EXP_PHASE, 1, -0x1D57C4 / (bits / 2));
|
||||||
pfn(pfnparam, -3, 5);
|
pfn(pfnparam, PROGFN_PHASE_EXTENT, 2, 0x10000);
|
||||||
|
pfn(pfnparam, PROGFN_EXP_PHASE, 2, -0x1D57C4 / (bits - bits / 2));
|
||||||
|
pfn(pfnparam, PROGFN_PHASE_EXTENT, 3, 0x4000);
|
||||||
|
pfn(pfnparam, PROGFN_LIN_PHASE, 3, 5);
|
||||||
|
pfn(pfnparam, PROGFN_READY, 0, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't generate e; we just use a standard one always.
|
* We don't generate e; we just use a standard one always.
|
||||||
*/
|
*/
|
||||||
key->exponent = bignum_from_short(RSA_EXPONENT);
|
key->exponent = bignum_from_long(RSA_EXPONENT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate p and q: primes with combined length `bits', not
|
* Generate p and q: primes with combined length `bits', not
|
||||||
@ -77,8 +59,10 @@ int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn,
|
|||||||
* general that's slightly more fiddly to arrange. By choosing
|
* general that's slightly more fiddly to arrange. By choosing
|
||||||
* a prime e, we can simplify the criterion.)
|
* a prime e, we can simplify the criterion.)
|
||||||
*/
|
*/
|
||||||
key->p = primegen(bits / 2, RSA_EXPONENT, 1, 1, pfn, pfnparam);
|
key->p = primegen(bits / 2, RSA_EXPONENT, 1, NULL,
|
||||||
key->q = primegen(bits - bits / 2, RSA_EXPONENT, 1, 2, pfn, pfnparam);
|
1, pfn, pfnparam);
|
||||||
|
key->q = primegen(bits - bits / 2, RSA_EXPONENT, 1, NULL,
|
||||||
|
2, pfn, pfnparam);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure p > q, by swapping them if not.
|
* Ensure p > q, by swapping them if not.
|
||||||
@ -94,21 +78,21 @@ int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn,
|
|||||||
* the other helpful quantities: n=pq, d=e^-1 mod (p-1)(q-1),
|
* the other helpful quantities: n=pq, d=e^-1 mod (p-1)(q-1),
|
||||||
* and (q^-1 mod p).
|
* and (q^-1 mod p).
|
||||||
*/
|
*/
|
||||||
pfn(pfnparam, 3, 1);
|
pfn(pfnparam, PROGFN_PROGRESS, 3, 1);
|
||||||
key->modulus = bigmul(key->p, key->q);
|
key->modulus = bigmul(key->p, key->q);
|
||||||
pfn(pfnparam, 3, 2);
|
pfn(pfnparam, PROGFN_PROGRESS, 3, 2);
|
||||||
pm1 = copybn(key->p);
|
pm1 = copybn(key->p);
|
||||||
decbn(pm1);
|
decbn(pm1);
|
||||||
qm1 = copybn(key->q);
|
qm1 = copybn(key->q);
|
||||||
decbn(qm1);
|
decbn(qm1);
|
||||||
phi_n = bigmul(pm1, qm1);
|
phi_n = bigmul(pm1, qm1);
|
||||||
pfn(pfnparam, 3, 3);
|
pfn(pfnparam, PROGFN_PROGRESS, 3, 3);
|
||||||
freebn(pm1);
|
freebn(pm1);
|
||||||
freebn(qm1);
|
freebn(qm1);
|
||||||
key->private_exponent = modinv(key->exponent, phi_n);
|
key->private_exponent = modinv(key->exponent, phi_n);
|
||||||
pfn(pfnparam, 3, 4);
|
pfn(pfnparam, PROGFN_PROGRESS, 3, 4);
|
||||||
key->iqmp = modinv(key->q, key->p);
|
key->iqmp = modinv(key->q, key->p);
|
||||||
pfn(pfnparam, 3, 5);
|
pfn(pfnparam, PROGFN_PROGRESS, 3, 5);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clean up temporary numbers.
|
* Clean up temporary numbers.
|
||||||
|
13
sshsha.c
13
sshsha.c
@ -271,6 +271,19 @@ static int sha1_verify(unsigned char *blk, int len, unsigned long seq)
|
|||||||
return !memcmp(correct, blk + len, 20);
|
return !memcmp(correct, blk + len, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hmac_sha1_simple(void *key, int keylen, void *data, int datalen,
|
||||||
|
unsigned char *output) {
|
||||||
|
SHA_State s1, s2;
|
||||||
|
unsigned char intermediate[20];
|
||||||
|
|
||||||
|
sha1_key(&s1, &s2, key, keylen);
|
||||||
|
SHA_Bytes(&s1, data, datalen);
|
||||||
|
SHA_Final(&s1, intermediate);
|
||||||
|
|
||||||
|
SHA_Bytes(&s2, intermediate, 20);
|
||||||
|
SHA_Final(&s2, output);
|
||||||
|
}
|
||||||
|
|
||||||
const struct ssh_mac ssh_sha1 = {
|
const struct ssh_mac ssh_sha1 = {
|
||||||
sha1_cskey, sha1_sckey,
|
sha1_cskey, sha1_sckey,
|
||||||
sha1_generate,
|
sha1_generate,
|
||||||
|
Loading…
Reference in New Issue
Block a user