mirror of
https://github.com/clearml/dropbear
synced 2025-06-26 18:17:32 +00:00
Compare commits
70 Commits
DROPBEAR_2
...
DROPBEAR_2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e10af850b | ||
|
|
ee4b4db816 | ||
|
|
ab9cfce00d | ||
|
|
2b8106b14e | ||
|
|
78c5daee52 | ||
|
|
2301b6ac0b | ||
|
|
a27e8b053e | ||
|
|
6145289e0d | ||
|
|
d14ebdbf0e | ||
|
|
4b305c5721 | ||
|
|
615885be01 | ||
|
|
6b823d617c | ||
|
|
ec993dbdbc | ||
|
|
ad1e9b7e3c | ||
|
|
846b8cdbf7 | ||
|
|
b0243b0e7b | ||
|
|
4faf06aae7 | ||
|
|
07d46f9907 | ||
|
|
413eaf1ba1 | ||
|
|
3b359050b4 | ||
|
|
a015cc7594 | ||
|
|
dc12be0cfe | ||
|
|
89e98a2f83 | ||
|
|
5027bc4db1 | ||
|
|
630f6aa6b9 | ||
|
|
8048473eb9 | ||
|
|
4216c984ae | ||
|
|
6abf756e51 | ||
|
|
b4bd23b4d2 | ||
|
|
724e61f8ae | ||
|
|
49667a82de | ||
|
|
a57114e7fa | ||
|
|
cfe90bc6bd | ||
|
|
0aefec6c89 | ||
|
|
6a3bc73a78 | ||
|
|
73aa4f0de9 | ||
|
|
9e25854b41 | ||
|
|
d277f140ba | ||
|
|
61267f8503 | ||
|
|
d3d0d60076 | ||
|
|
91e537e427 | ||
|
|
fb9a78c3ee | ||
|
|
8f8a3dff70 | ||
|
|
c917807b1c | ||
|
|
701d43b859 | ||
|
|
79bedc90a1 | ||
|
|
545cc62671 | ||
|
|
331d4a714f | ||
|
|
2a81289ed3 | ||
|
|
5acee497bf | ||
|
|
972d723484 | ||
|
|
7dc2f36c3e | ||
|
|
90cfbe1f7a | ||
|
|
b681570899 | ||
|
|
201e359363 | ||
|
|
fa4c4646d8 | ||
|
|
6f6aa9db5a | ||
|
|
e35d0784a8 | ||
|
|
cc6fa57a41 | ||
|
|
a26ad21c0a | ||
|
|
002b79e2f9 | ||
|
|
3d12521735 | ||
|
|
b2007beeb0 | ||
|
|
8f123fb618 | ||
|
|
c71258625d | ||
|
|
615ed4e46a | ||
|
|
fa116e983b | ||
|
|
8c6aaf8d36 | ||
|
|
cae6e6af10 | ||
|
|
f89c5b0390 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -5,6 +5,7 @@
|
||||
*.bb
|
||||
*.bbg
|
||||
*.prof
|
||||
.*.swp
|
||||
/autom4te.cache
|
||||
/config.log
|
||||
/config.status
|
||||
@@ -13,6 +14,9 @@
|
||||
/dropbearconvert
|
||||
/dropbearkey
|
||||
/dropbearmulti
|
||||
/fuzzcorpus
|
||||
/fuzzer-*
|
||||
/fuzzer-*.options
|
||||
/scp
|
||||
/scp-progress
|
||||
Makefile
|
||||
@@ -20,3 +24,4 @@ config.h
|
||||
config.h.in
|
||||
configure
|
||||
default_options_guard.h
|
||||
tags
|
||||
|
||||
1
.hgsigs
1
.hgsigs
@@ -25,3 +25,4 @@ fd1981f41c626a969f07b4823848deaefef3c8aa 0 iQIcBAABCgAGBQJW4W2TAAoJEESTFJTynGdzu
|
||||
5c9207ceedaea794f958224c19214d66af6e2d56 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlkdtooACgkQRJMUlPKcZ3P6ZxAAmLy/buZB/d96DJF/pViRWt/fWdjQFC4MqWfeSLW02OZ8Qkm1vPL3ln6WPHC2thy3xZWVg2uan3pLk/XXnsIFu8Q7r1EAfFFpvlMUmdl7asE8V6ilaeqmiI7bIvGMFbf4cZkQliLjiFkJX56tFHRCNi+rb7WgRuru3/GzPXUq2AvXZvFpFJgik0B72TxVlmCKeBRZq1FvP0UhAH48RJWYJksdEyzh2paMfjX9ZO5Q2SFFrmPw6k2ArdJFC1AYcgceZC84y06RKJ0WiSntUPlEUXgQbQVVWbtQDhjfJXMr/beuroNdT/vsRraLVkAzvhaDXNnHlAJNLQxci+AcLpnzZhxMW+ax7RRtrpXGxRN4cs0lBGUcSkaDybFqMYXwEjXAE8w6fdJRWCIlxctkAW/iNEO4kAG97hI2Qwcw5oU2Ymnv09zyGR+XJE35pJqPulJHExdwanJHvmjH0QF7TNFS82yxS5dKnP954cj3Lu9SWGYWjxQJRmLtOwb+lqqol4VTxG7Ois4uef9/Tpp9skeMZXVeNlpn2wrp6iFcX3uiiVDg9VKkl3ig6UqCiqQSuiIN87RXwUOeHXlCnW3adz3Xei0ziBrwLSql7lBIHGEAlUUNmJ3CrR8IwQtcynGEMKfNIeZ/XK+uNlm9cJIqZf1fzqc8KexlyS9AS0i/kiYZTr4=
|
||||
2f0c3f3361d3ea4eb9129ed8810699fda7e7a8ee 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlqVb+IACgkQRJMUlPKcZ3OENA//R9HsOUJQB2QZjRgAvqgLn2AMLUvmWb2etTZEc3Nps957Fw1F4kjh6VGfIpWuytfsDx1W8qRx09ikTdb3YteMWCuX8/aFreSPrioYmzrAEcxkZdA7B/jciqU0iXuHiJ9saKk5TR70aNp+iRy0hjAgiYEsVMF9YKHzULOJcHr70x9XVKquubQkwNqJA+/b2JbK2j46wM5nVK/alGSI2kMmEzXmAHQxsvf1OLMvgH8ou/l0xsg/CuFEK299XKfZAbsFEXrjuoWZ1aSa6rTeOWsWli5T+czyyJHI4Eu0Sz/gaR8+MPhJSYes8YjvzEdv32rRMDVOdBq4e+HoTgFt/THYABP6/R1H5fX3Lm4K8u9F9SwJbb/YKRAIrfWDob8ApnGFHk2dyYO20Fskbbg6b1pC7ulDWsufu8lYkQyMlTc3dR6P4eTB6mKO4x+gMG6tIYZ60fiULoEnMJCgegPtevmz+TG1rzdjh3ljiw9Dxz5lNtL+W7sBKKHwhyG0u+bavgmvBMKNL/rdHEM+0yCIz1U6Lb8sVaST1E4zbdm7cWHbSozBij3G0GBSkLFEq7ZLlh8wco9rELRh0Y9fFsWY9j6H/PTOu0GfHrYluFb9WGywHAquQY8j2croRx+MrvTbR1wZrbevPNm9gqk3vgOiDWu7KwxLLqcj+dEQ7tccptVYtbM=
|
||||
07b0d56d186d7eeef4106137a3eba554959ba0e3 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlyWOo8ACgkQRJMUlPKcZ3O+MQ//c5oeDUvZuFiI4FHZqfIK/59YAciTP+9TQmoWDVSuOdkd9ZYJA7b7DCusqP2TWFEIl9M7i5hTLTMD21xuEQQtfOSP6EXpUw6JNdh/lsJs7EDlFANtwkdEozAQozFKnXbJEV3y9WldEWUlmPFjt4fJQIuG10SU7MTJHcSaQddJCh3I1//F4EvgRe+OqyrFwKekGiFdvfjcIFN3lQmk6K1Sc0MgyIO/VVZm/AQpBi0Dlg0yOl+EDcxxlmeSInbvLceWSP6op35I4dE5YWH1UetjzIsr5AIM15/k3viAKDDefY1EMAzK9b7YAF4BLw0a6XoQu0apvcWaALE/bJzWNSg/QbCm2JAZzk21WLLvR+AELzPfKXrHX3o0h51lpQ4rs7EWKUm43dJPoWkcFNOU+BDsNzffcJgChbRs48ut89DYLiGmSxhRxE77VPbA+klgTGdctOTLd8psseRlGYCuGe8zeota80bV9fUZ9WJZHwNgEWGowKUoTjy6l5k9OH3iQuQX3OXoy78ufRgWDulE7noVTMhXurQ8a0Jf2k/MW9dcnqGVkWitCFKPEvZwVmWyW2AWsdMcBJnFFGzDsNSxWTtCF9XcxieDO1IB8vGwYcb1TwEVuVzvR/wwvc3PgVikF+4Qv2NqdoQc1yn2PkocY2hwXyIZUAwz7erNumlTbeC/JK8=
|
||||
ebcdb893992d286d363e60f5353d6e1401e7084b 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlybhXAACgkQRJMUlPKcZ3O7pQ//QuNJfBVa7ROaOJOR2H/xr6PRn1Fnc6rr/GCF9cqWrbGP6wNo24dRjcu5LxviqPvzfwRXIMXwVz8L/y61/sm6XcA7VFP4+MBoltfeUOdMbfBdtwEUo3WMBdP1w2q5GgYj8ZY6MawiLEqFba5aua7dokTNBOQM3Yebj+9I16MiWEaRSnuwYPoieHW2Fo6oftcIgs/GCXwT2xYzc0n3FpYAbK7u6sEkpL16EstV0Y/G70+X1/4Mg3GM96S5fl9Zbun47W7/+gT4AQVQjE+UnPNDudObAe+2BaOZLFvEbd7iJBBcqtjpBktuP58IEAb3A3srUCy49LNLWk43lj+PtoslK/U6TShKQ2vAgfd//bbn6ieXFJY8N+wYPpJo1m7zpTiEtS7J7wu6vkGGZlqUAj6MHXZj223CgazhSAlg/XFPs9oz3Y96c33Tnd4jB9iEXNNt5jzCAMImx2huSGgnP0JFAbcniq/ug5tl1VWaracvSuJl7fmf17DbmehsLbvtZBoMlePY7Ssfb5IokfVvptt4zRpRZnjtWfHCjtC6zYhtvXTmXH/bqWwx9MMjOf5WPfZoCMvXfMqdVI15FVbxU15WnqjvdvKUCkdz1aMFzxqc4MXgyvjtB9CvO/8WwBOJ2m2nDdiZfh8/H8SawYqEHgB61FX5xA5aXecgXcjQnqWDDxw=
|
||||
|
||||
1
.hgtags
1
.hgtags
@@ -57,3 +57,4 @@ cbd674d63cd4f3781464a8d4056a5506c8ae926f DROPBEAR_2015.67
|
||||
c31276613181c5cff7854e7ef586ace03424e55e DROPBEAR_2017.75
|
||||
1c66ca4f3791c82501c88e7637312182c7294978 DROPBEAR_2018.76
|
||||
6d1bbe7d5fa5827c7eae28bca044d691f7efa785 DROPBEAR_2019.77
|
||||
009d52ae26d35f3381c801e02318fa9be34be93c DROPBEAR_2019.78
|
||||
|
||||
38
.travis.yml
38
.travis.yml
@@ -3,30 +3,34 @@ language: c
|
||||
git:
|
||||
depth: 3
|
||||
|
||||
# use focal which provides libtommath 1.20
|
||||
dist: focal
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# subsequent matrix options use these first settings
|
||||
- os: linux
|
||||
- name: "plain linux"
|
||||
compiler: gcc
|
||||
env: WEXTRAFLAGS=-Werror
|
||||
sudo: false
|
||||
- env: MULTI=1 WEXTRAFLAGS=-Werror
|
||||
# libtom has some warnings, so no WEXTRAFLAGS
|
||||
- env: CONFIGURE_FLAGS=--enable-bundled-libtom WEXTRAFLAGS=""
|
||||
- env: NOWRITEV=1 WEXTRAFLAGS=-Werror
|
||||
# libtomcrypt 1.18.1 fixes clang problems, distro doesn't have that yet
|
||||
- os: linux
|
||||
- name: "multi binary"
|
||||
env: MULTI=1 WEXTRAFLAGS=-Werror
|
||||
- name: "bundled libtom, xenial, no writev()"
|
||||
# NOWRITEV is unrelated to libtom/xenial, test here to save a job
|
||||
env: CONFIGURE_FLAGS=--enable-bundled-libtom WEXTRAFLAGS=-Werror NOWRITEV=1
|
||||
# can use an older distro with bundled libtom
|
||||
dist: xenial
|
||||
- name: "linux clang"
|
||||
os: linux
|
||||
compiler: clang
|
||||
env: CONFIGURE_FLAGS=--enable-bundled-libtom WEXTRAFLAGS=""
|
||||
- os: osx
|
||||
env: WEXTRAFLAGS=-Werror
|
||||
- name: "osx"
|
||||
os: osx
|
||||
compiler: clang
|
||||
env: WEXTRAFLAGS=""
|
||||
|
||||
# OS X says daemon() and utmp are deprecated
|
||||
env: WEXTRAFLAGS="-Wno-deprecated-declarations -Werror"
|
||||
# Note: the fuzzing malloc wrapper doesn't replace free() in system libtomcrypt, so need bundled.
|
||||
- env: DO_FUZZ=1 CONFIGURE_FLAGS="--enable-fuzz --disable-harden --enable-bundled-libtom" WEXTRAFLAGS="" LDFLAGS=-fsanitize=address EXTRACFLAGS=-fsanitize=address CXX=clang++
|
||||
- name: "fuzzing"
|
||||
env: DO_FUZZ=1 CONFIGURE_FLAGS="--enable-fuzz --disable-harden --enable-bundled-libtom" WEXTRAFLAGS=-Werror LDFLAGS=-fsanitize=address EXTRACFLAGS=-fsanitize=address CXX=clang++
|
||||
compiler: clang
|
||||
# sanitizers need ptrace which is privileged https://github.com/travis-ci/travis-ci/issues/9033
|
||||
sudo: required
|
||||
|
||||
# container-based builds
|
||||
addons:
|
||||
@@ -46,6 +50,7 @@ install:
|
||||
- autoheader
|
||||
- ./configure $CONFIGURE_FLAGS CFLAGS="-O2 -Wall -Wno-pointer-sign $WEXTRAFLAGS $EXTRACFLAGS" --prefix="$HOME/inst" || (cat config.log; exit 1)
|
||||
- if [ "$NOWRITEV" = "1" ]; then sed -i -e s/HAVE_WRITEV/DONT_HAVE_WRITEV/ config.h ; fi
|
||||
- make lint
|
||||
- make -j3
|
||||
- test -z $DO_FUZZ || make fuzzstandalone
|
||||
# avoid concurrent install, osx/freebsd is racey (https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=208093)
|
||||
@@ -57,6 +62,7 @@ script:
|
||||
- ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
|
||||
- ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384
|
||||
- ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521
|
||||
- ~/inst/bin/dropbearkey -t ed25519 -f tested25519
|
||||
- test -z $DO_FUZZ || ./fuzzers_test.sh
|
||||
|
||||
branches:
|
||||
|
||||
54
CHANGES
54
CHANGES
@@ -1,3 +1,57 @@
|
||||
2020.79 - 15 June 2020
|
||||
|
||||
- Support ed25519 hostkeys and authorized_keys, many thanks to Vladislav Grishenko.
|
||||
This also replaces curve25519 with a TweetNaCl implementation that reduces code size.
|
||||
|
||||
- Add chacha20-poly1305 authenticated cipher. This will perform faster than AES
|
||||
on many platforms. Thanks to Vladislav Grishenko
|
||||
|
||||
- Support using rsa-sha2 signatures. No changes are needed to hostkeys/authorized_keys
|
||||
entries, existing RSA keys can be used with the new signature format (signatures
|
||||
are ephemeral within a session). Old ssh-rsa signatures will no longer
|
||||
be supported by OpenSSH in future so upgrading is recommended.
|
||||
|
||||
- Use getrandom() call on Linux to ensure sufficient entropy has been gathered at startup.
|
||||
Dropbear now avoids reading from the random source at startup, instead waiting until
|
||||
the first connection. It is possible that some platforms were running without enough
|
||||
entropy previously, those could potentially block at first boot generating host keys.
|
||||
The dropbear "-R" option is one way to avoid that.
|
||||
|
||||
- Upgrade libtomcrypt to 1.18.2 and libtommath to 1.2.0, many thanks to Steffen Jaeckel for
|
||||
updating Dropbear to use the current API. Dropbear's configure script will check
|
||||
for sufficient system library versions, otherwise using the bundled versions.
|
||||
|
||||
- CBC ciphers, 3DES, hmac-sha1-96, and x11 forwarding are now disabled by default.
|
||||
They can be set in localoptions.h if required.
|
||||
Blowfish has been removed.
|
||||
|
||||
- Support AES GCM, patch from Vladislav Grishenko. This is disabled by default,
|
||||
Dropbear doesn't currently use hardware accelerated AES.
|
||||
|
||||
- Added an API for specifying user public keys as an authorized_keys replacement.
|
||||
See pubkeyapi.h for details, thanks to Fabrizio Bertocci
|
||||
|
||||
- Fix idle detection clashing with keepalives, thanks to jcmathews
|
||||
|
||||
- Include IP addresses in more early exit messages making it easier for fail2ban
|
||||
processing. Patch from Kevin Darbyshire-Bryant
|
||||
|
||||
- scp fix for CVE-2018-20685 where a server could modify name of output files
|
||||
|
||||
- SSH_ORIGINAL_COMMAND is set for "dropbear -c" forced command too
|
||||
|
||||
- Fix writing key files on systems without hard links, from Matt Robinson
|
||||
|
||||
- Compatibility fixes for IRIX from Kazuo Kuroi
|
||||
|
||||
- Re-enable printing MOTD by default, was lost moving from options.h. Thanks to zciendor
|
||||
|
||||
- Call fsync() is called on parent directory when writing key files to ensure they are flushed
|
||||
|
||||
- Fix "make install" for manpages in out-of-tree builds, from Gabor Z. Papp
|
||||
|
||||
- Some notes are added in DEVELOPER.md
|
||||
|
||||
2019.78 - 27 March 2019
|
||||
|
||||
- Fix dbclient regression in 2019.77. After exiting the terminal would be left
|
||||
|
||||
51
DEVELOPING.md
Normal file
51
DEVELOPING.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Developer Notes
|
||||
|
||||
## Building
|
||||
|
||||
See [INSTALL](INSTALL) for build instructions.
|
||||
[SMALL](SMALL) has hints for building smaller binaries, also see comments
|
||||
in default_options.h.
|
||||
|
||||
## Debug printing
|
||||
|
||||
Set `#define DEBUG_TRACE 1` in localoptions.h to enable a `-v` option
|
||||
for dropbear and dbclient. That prints various details of the session. For
|
||||
development running `dropbear -F -E` is useful to run in the foreground. You
|
||||
can set `#define DEBUG_NOFORK 1` to make dropbear a one-shot server, easy to
|
||||
run under a debugger.
|
||||
|
||||
## Random sources
|
||||
|
||||
Most cryptography requires a good random entropy source, both to generate secret
|
||||
keys and in the course of a session. Dropbear uses the Linux kernel's
|
||||
`getrandom()` syscall to ensure that the system RNG has been initialised before
|
||||
using it. On some systems there is insufficient entropy gathered during early
|
||||
boot - generating hostkeys then will block for some amount of time.
|
||||
Dropbear has a `-R` option to generate hostkeys upon the first connection
|
||||
as required - that will allow the system more time to gather entropy.
|
||||
|
||||
## Algorithms
|
||||
|
||||
Default algorithm lists are specified in [common-algo.c](common-algo.c).
|
||||
They are in priority order, the client's first matching choice is used
|
||||
(see rfc4253).
|
||||
Dropbear client has `-c` and `-m` arguments to choose which are enabled at
|
||||
runtime (doesn't work for server as of June 2020).
|
||||
|
||||
Enabling/disabling algorithms is done in [localoptions.h](localoptions.h),
|
||||
see [default_options.h](default_options.h).
|
||||
|
||||
## Non-root user
|
||||
|
||||
Dropbear server will run fine as a non-root user, allowing logins only for
|
||||
that user. Password authentication probably won't work (can't read shadow
|
||||
passwords). You will need to create hostkeys that are readable.
|
||||
|
||||
## Connection setup
|
||||
|
||||
Dropbear implements first_kex_packet_follows to reduce
|
||||
handshake latency (rfc 4253 7.1). Some less common implementations don't
|
||||
handle that, it can be a cause of problems connecting. Note also that
|
||||
Dropbear may send several ssh packets within a single TCP packet - it's just a
|
||||
stream.
|
||||
|
||||
@@ -72,3 +72,6 @@ Current fuzzers are
|
||||
|
||||
- [fuzzer-kexecdh](fuzzer-kexecdh.c) - test Elliptic Curve Diffie-Hellman key exchange like fuzzer-kexdh.
|
||||
This is testing libtommath ECC routines.
|
||||
|
||||
- [fuzzer-kexcurve25519](fuzzer-kexcurve25519.c) - test Curve25519 Elliptic Curve Diffie-Hellman key exchange
|
||||
like fuzzer-kexecdh. This is testing `dropbear_curve25519_scalarmult()` and other libtommath routines.
|
||||
|
||||
4
INSTALL
4
INSTALL
@@ -28,6 +28,8 @@ Basic Dropbear build instructions:
|
||||
recompile after changing the PROGRAMS list, you *MUST* "make clean" before
|
||||
recompiling - bad things will happen otherwise)
|
||||
|
||||
DEVELOPING.md has some notes on other developer topics, including debugging.
|
||||
|
||||
See MULTI for instructions on making all-in-one binaries.
|
||||
|
||||
If you want to compile statically use ./configure --enable-static
|
||||
@@ -56,7 +58,7 @@ Compiling for uClibc should be the same as normal, just set CC to the magic
|
||||
uClibc toolchain compiler (ie export CC=i386-uclibc-gcc or whatever).
|
||||
You can use "make STATIC=1" to make statically linked binaries, and it is
|
||||
advisable to strip the binaries too. If you're looking to make a small binary,
|
||||
you should remove unneeded ciphers and MD5, by editing options.h
|
||||
you should remove unneeded ciphers and MD5, by editing localoptions.h
|
||||
|
||||
It is possible to compile zlib in, by copying zlib.h and zconf.h into a
|
||||
subdirectory (ie zlibincludes), and
|
||||
|
||||
68
LICENSE
68
LICENSE
@@ -90,52 +90,24 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
=====
|
||||
|
||||
curve25519-donna:
|
||||
curve25519.c:
|
||||
|
||||
/* Copyright 2008, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* curve25519-donna: Curve25519 elliptic curve, public key function
|
||||
*
|
||||
* http://code.google.com/p/curve25519-donna/
|
||||
*
|
||||
* Adam Langley <agl@imperialviolet.org>
|
||||
*
|
||||
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
|
||||
*
|
||||
* More information about curve25519 can be found here
|
||||
* http://cr.yp.to/ecdh.html
|
||||
*
|
||||
* djb's sample implementation of curve25519 is written in a special assembly
|
||||
* language called qhasm and uses the floating point registers.
|
||||
*
|
||||
* This is, almost, a clean room reimplementation from the curve25519 paper. It
|
||||
* uses many of the tricks described therein. Only the crecip function is taken
|
||||
* from the sample implementation.
|
||||
*/
|
||||
Modified TweetNaCl version 20140427, a self-contained public-domain C library.
|
||||
https://tweetnacl.cr.yp.to/
|
||||
|
||||
Contributors (alphabetical order)
|
||||
Daniel J. Bernstein, University of Illinois at Chicago and Technische
|
||||
Universiteit Eindhoven
|
||||
Bernard van Gastel, Radboud Universiteit Nijmegen
|
||||
Wesley Janssen, Radboud Universiteit Nijmegen
|
||||
Tanja Lange, Technische Universiteit Eindhoven
|
||||
Peter Schwabe, Radboud Universiteit Nijmegen
|
||||
Sjaak Smetsers, Radboud Universiteit Nijmegen
|
||||
|
||||
Acknowledgments
|
||||
This work was supported by the U.S. National Science Foundation under grant
|
||||
1018836. "Any opinions, findings, and conclusions or recommendations expressed
|
||||
in this material are those of the author(s) and do not necessarily reflect the
|
||||
views of the National Science Foundation."
|
||||
This work was supported by the Netherlands Organisation for Scientific
|
||||
Research (NWO) under grant 639.073.005 and Veni 2013 project 13114.
|
||||
|
||||
46
Makefile.in
46
Makefile.in
@@ -36,8 +36,9 @@ COMMONOBJS=dbutil.o buffer.o dbhelpers.o \
|
||||
queue.o \
|
||||
atomicio.o compat.o fake-rfc2553.o \
|
||||
ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
|
||||
curve25519.o ed25519.o \
|
||||
dbmalloc.o \
|
||||
gensignkey.o gendss.o genrsa.o
|
||||
gensignkey.o gendss.o genrsa.o gened25519.o
|
||||
|
||||
SVROBJS=svr-kex.o svr-auth.o sshpty.o \
|
||||
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
|
||||
@@ -52,7 +53,7 @@ CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
|
||||
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
|
||||
common-channel.o common-chansession.o termcodes.o loginrec.o \
|
||||
tcp-accept.o listener.o process-packet.o dh_groups.o \
|
||||
common-runopts.o circbuffer.o curve25519-donna.o list.o netio.o
|
||||
common-runopts.o circbuffer.o list.o netio.o chachapoly.o gcm.o
|
||||
|
||||
KEYOBJS=dropbearkey.o
|
||||
|
||||
@@ -80,6 +81,15 @@ else
|
||||
scpobjs=$(SCPOBJS)
|
||||
endif
|
||||
|
||||
ifeq (@DROPBEAR_PLUGIN@, 1)
|
||||
# rdynamic makes all the global symbols of dropbear available to all the loaded shared libraries
|
||||
# this allow a plugin to reuse existing crypto/utilities like base64_decode/base64_encode without
|
||||
# the need to rewrite them.
|
||||
PLUGIN_LIBS=-ldl -rdynamic
|
||||
else
|
||||
PLUGIN_LIBS=
|
||||
endif
|
||||
|
||||
VPATH=@srcdir@
|
||||
srcdir=@srcdir@
|
||||
|
||||
@@ -165,7 +175,7 @@ insmulti%: dropbearmulti$(EXEEXT)
|
||||
-rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
|
||||
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
if test -e $(srcdir)/$*.1; then $(INSTALL) -m 644 $(srcdir)/$*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
|
||||
# dropbear should go in sbin, so it needs a separate rule
|
||||
inst_dropbear: dropbear
|
||||
@@ -178,7 +188,7 @@ inst_%: %
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
$(INSTALL) $*$(EXEEXT) $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
|
||||
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
if test -e $(srcdir)/$*.1; then $(INSTALL) -m 644 $(srcdir)/$*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
|
||||
inst_dropbearmulti: $(addprefix insmulti, $(PROGRAMS))
|
||||
|
||||
@@ -189,7 +199,7 @@ dropbearkey: $(dropbearkeyobjs)
|
||||
dropbearconvert: $(dropbearconvertobjs)
|
||||
|
||||
dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@ $(PLUGIN_LIBS)
|
||||
|
||||
dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
|
||||
@@ -226,7 +236,7 @@ $(STATIC_LTC): $(OPTION_HEADERS)
|
||||
$(STATIC_LTM): $(OPTION_HEADERS)
|
||||
$(MAKE) -C libtommath
|
||||
|
||||
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean
|
||||
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean lint
|
||||
|
||||
ltc-clean:
|
||||
$(MAKE) -C libtomcrypt clean
|
||||
@@ -252,10 +262,13 @@ distclean: clean tidy
|
||||
tidy:
|
||||
-rm -f *~ *.gcov */*~
|
||||
|
||||
lint:
|
||||
cd $(srcdir); ./dropbear_lint.sh
|
||||
|
||||
## Fuzzing targets
|
||||
|
||||
# list of fuzz targets
|
||||
FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh
|
||||
FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519
|
||||
|
||||
FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS))
|
||||
|
||||
@@ -269,27 +282,32 @@ fuzzstandalone: fuzz-harness.o fuzz-targets
|
||||
# exclude svr-main.o to avoid duplicate main
|
||||
svrfuzzobjs=$(subst svr-main.o, ,$(dropbearobjs))
|
||||
|
||||
fuzz-harness.o: $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs) fuzz-common.o
|
||||
|
||||
# build all the fuzzers. This will require fail to link unless built with
|
||||
# make fuzz-targets FUZZLIB=-lFuzzer.a
|
||||
# or similar - the library provides main().
|
||||
fuzz-targets: $(FUZZ_TARGETS) $(FUZZER_OPTIONS)
|
||||
|
||||
fuzzer-preauth: fuzzer-preauth.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
|
||||
fuzzer-preauth: fuzzer-preauth.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
|
||||
fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-pubkey: fuzzer-pubkey.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
|
||||
fuzzer-pubkey: fuzzer-pubkey.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-verify: fuzzer-verify.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
|
||||
fuzzer-verify: fuzzer-verify.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-kexdh: fuzzer-kexdh.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
|
||||
fuzzer-kexdh: fuzzer-kexdh.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-kexecdh: fuzzer-kexecdh.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
|
||||
fuzzer-kexecdh: fuzzer-kexecdh.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-kexcurve25519: fuzzer-kexcurve25519.o fuzz-harness.o
|
||||
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
|
||||
|
||||
fuzzer-%.options: Makefile
|
||||
@@ -302,7 +320,9 @@ fuzz-hostkeys:
|
||||
dropbearkey -t rsa -f keyr
|
||||
dropbearkey -t dss -f keyd
|
||||
dropbearkey -t ecdsa -size 256 -f keye
|
||||
dropbearkey -t ed25519 -f keyed25519
|
||||
echo > hostkeys.c
|
||||
/usr/bin/xxd -i -a keyr >> hostkeys.c
|
||||
/usr/bin/xxd -i -a keye >> hostkeys.c
|
||||
/usr/bin/xxd -i -a keyd >> hostkeys.c
|
||||
/usr/bin/xxd -i -a keyed25519 >> hostkeys.c
|
||||
|
||||
1
README
1
README
@@ -55,6 +55,7 @@ To run the server, you need to generate server keys, this is one-off:
|
||||
./dropbearkey -t rsa -f dropbear_rsa_host_key
|
||||
./dropbearkey -t dss -f dropbear_dss_host_key
|
||||
./dropbearkey -t ecdsa -f dropbear_ecdsa_host_key
|
||||
./dropbearkey -t ed25519 -f dropbear_ed25519_host_key
|
||||
|
||||
or alternatively convert OpenSSH keys to Dropbear:
|
||||
./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
|
||||
/* From OpenSSH authfd.h */
|
||||
#define SSH_AGENT_RSA_SHA2_256 0x02
|
||||
|
||||
/* An agent reply can be reasonably large, as it can
|
||||
* contain a list of all public keys held by the agent.
|
||||
* 10000 is arbitrary */
|
||||
@@ -40,7 +43,7 @@
|
||||
/* client functions */
|
||||
void cli_load_agent_keys(m_list * ret_list);
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const buffer *data_buf);
|
||||
const buffer *data_buf, enum signature_type type);
|
||||
void cli_setup_agent(const struct Channel *channel);
|
||||
|
||||
#ifdef __hpux
|
||||
|
||||
26
algo.h
26
algo.h
@@ -47,7 +47,7 @@ typedef struct Algo_Type algo_type;
|
||||
|
||||
/* lists mapping ssh types of algorithms to internal values */
|
||||
extern algo_type sshkex[];
|
||||
extern algo_type sshhostkey[];
|
||||
extern algo_type sigalgs[];
|
||||
extern algo_type sshciphers[];
|
||||
extern algo_type sshhashes[];
|
||||
extern algo_type ssh_compress[];
|
||||
@@ -72,6 +72,14 @@ struct dropbear_cipher_mode {
|
||||
unsigned long len, void *cipher_state);
|
||||
int (*decrypt)(const unsigned char *ct, unsigned char *pt,
|
||||
unsigned long len, void *cipher_state);
|
||||
int (*aead_crypt)(unsigned int seq,
|
||||
const unsigned char *in, unsigned char *out,
|
||||
unsigned long len, unsigned long taglen,
|
||||
void *cipher_state, int direction);
|
||||
int (*aead_getlength)(unsigned int seq,
|
||||
const unsigned char *in, unsigned int *outlen,
|
||||
unsigned long len, void *cipher_state);
|
||||
const struct dropbear_hash *aead_mac;
|
||||
};
|
||||
|
||||
struct dropbear_hash {
|
||||
@@ -112,21 +120,17 @@ struct dropbear_kex {
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
};
|
||||
|
||||
int have_algo(const char* algo, size_t algolen, const algo_type algos[]);
|
||||
/* Includes all algorithms is useall is set */
|
||||
void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall);
|
||||
/* Includes "usable" algorithms */
|
||||
void buf_put_algolist(buffer * buf, const algo_type localalgos[]);
|
||||
|
||||
enum kexguess2_used {
|
||||
KEXGUESS2_LOOK,
|
||||
KEXGUESS2_NO,
|
||||
KEXGUESS2_YES,
|
||||
};
|
||||
|
||||
#define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au"
|
||||
#define KEXGUESS2_ALGO_ID 99
|
||||
|
||||
|
||||
int buf_has_algo(buffer *buf, const char *algo);
|
||||
algo_type * first_usable_algo(algo_type algos[]);
|
||||
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
enum kexguess2_used *kexguess2, int *goodguess);
|
||||
int kexguess2, int *goodguess);
|
||||
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
int check_user_algos(const char* user_algo_list, algo_type * algos,
|
||||
|
||||
2
bignum.c
2
bignum.c
@@ -86,7 +86,7 @@ void m_mp_free_multi(mp_int **mp, ...)
|
||||
|
||||
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
|
||||
|
||||
if (mp_read_unsigned_bin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
|
||||
if (mp_from_ubin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
|
||||
dropbear_exit("Mem alloc error");
|
||||
}
|
||||
}
|
||||
|
||||
34
buffer.c
34
buffer.c
@@ -228,19 +228,37 @@ char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
}
|
||||
|
||||
/* Return a string as a newly allocated buffer */
|
||||
buffer * buf_getstringbuf(buffer *buf) {
|
||||
static buffer * buf_getstringbuf_int(buffer *buf, int incllen) {
|
||||
buffer *ret = NULL;
|
||||
unsigned int len = buf_getint(buf);
|
||||
int extra = 0;
|
||||
if (len > MAX_STRING_LEN) {
|
||||
dropbear_exit("String too long");
|
||||
}
|
||||
ret = buf_new(len);
|
||||
if (incllen) {
|
||||
extra = 4;
|
||||
}
|
||||
ret = buf_new(len+extra);
|
||||
if (incllen) {
|
||||
buf_putint(ret, len);
|
||||
}
|
||||
memcpy(buf_getwriteptr(ret, len), buf_getptr(buf, len), len);
|
||||
buf_incrpos(buf, len);
|
||||
buf_incrlen(ret, len);
|
||||
buf_setpos(ret, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return a string as a newly allocated buffer */
|
||||
buffer * buf_getstringbuf(buffer *buf) {
|
||||
return buf_getstringbuf_int(buf, 0);
|
||||
}
|
||||
|
||||
/* Returns a string in a new buffer, including the length */
|
||||
buffer * buf_getbuf(buffer *buf) {
|
||||
return buf_getstringbuf_int(buf, 1);
|
||||
}
|
||||
|
||||
/* Just increment the buffer position the same as if we'd used buf_getstring,
|
||||
* but don't bother copying/malloc()ing for it */
|
||||
void buf_eatstring(buffer *buf) {
|
||||
@@ -289,18 +307,18 @@ void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
|
||||
/* for our purposes we only need positive (or 0) numbers, so will
|
||||
* fail if we get negative numbers */
|
||||
void buf_putmpint(buffer* buf, mp_int * mp) {
|
||||
|
||||
size_t written;
|
||||
unsigned int len, pad = 0;
|
||||
TRACE2(("enter buf_putmpint"))
|
||||
|
||||
dropbear_assert(mp != NULL);
|
||||
|
||||
if (SIGN(mp) == MP_NEG) {
|
||||
if (mp_isneg(mp)) {
|
||||
dropbear_exit("negative bignum");
|
||||
}
|
||||
|
||||
/* zero check */
|
||||
if (USED(mp) == 1 && DIGIT(mp, 0) == 0) {
|
||||
if (mp_iszero(mp)) {
|
||||
len = 0;
|
||||
} else {
|
||||
/* SSH spec requires padding for mpints with the MSB set, this code
|
||||
@@ -321,10 +339,10 @@ void buf_putmpint(buffer* buf, mp_int * mp) {
|
||||
if (pad) {
|
||||
buf_putbyte(buf, 0x00);
|
||||
}
|
||||
if (mp_to_unsigned_bin(mp, buf_getwriteptr(buf, len-pad)) != MP_OKAY) {
|
||||
if (mp_to_ubin(mp, buf_getwriteptr(buf, len-pad), len-pad, &written) != MP_OKAY) {
|
||||
dropbear_exit("mpint error");
|
||||
}
|
||||
buf_incrwritepos(buf, len-pad);
|
||||
buf_incrwritepos(buf, written);
|
||||
}
|
||||
|
||||
TRACE2(("leave buf_putmpint"))
|
||||
@@ -352,7 +370,7 @@ int buf_getmpint(buffer* buf, mp_int* mp) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
if (mp_read_unsigned_bin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
|
||||
if (mp_from_ubin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
1
buffer.h
1
buffer.h
@@ -58,6 +58,7 @@ unsigned char* buf_getptr(const buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getwriteptr(const buffer* buf, unsigned int len);
|
||||
char* buf_getstring(buffer* buf, unsigned int *retlen);
|
||||
buffer * buf_getstringbuf(buffer *buf);
|
||||
buffer * buf_getbuf(buffer *buf);
|
||||
void buf_eatstring(buffer *buf);
|
||||
void buf_putint(buffer* buf, unsigned int val);
|
||||
void buf_putstring(buffer* buf, const char* str, unsigned int len);
|
||||
|
||||
148
chachapoly.c
Normal file
148
chachapoly.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2020 by Vladislav Grishenko
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
#include "dbutil.h"
|
||||
#include "chachapoly.h"
|
||||
|
||||
#if DROPBEAR_CHACHA20POLY1305
|
||||
|
||||
#define CHACHA20_KEY_LEN 32
|
||||
#define CHACHA20_BLOCKSIZE 8
|
||||
#define POLY1305_KEY_LEN 32
|
||||
#define POLY1305_TAG_LEN 16
|
||||
|
||||
static const struct ltc_cipher_descriptor dummy = {.name = NULL};
|
||||
|
||||
static const struct dropbear_hash dropbear_chachapoly_mac =
|
||||
{NULL, POLY1305_KEY_LEN, POLY1305_TAG_LEN};
|
||||
|
||||
const struct dropbear_cipher dropbear_chachapoly =
|
||||
{&dummy, CHACHA20_KEY_LEN*2, CHACHA20_BLOCKSIZE};
|
||||
|
||||
static int dropbear_chachapoly_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
|
||||
const unsigned char *key, int keylen,
|
||||
int UNUSED(num_rounds), dropbear_chachapoly_state *state) {
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_chachapoly_start"))
|
||||
|
||||
if (keylen != CHACHA20_KEY_LEN*2) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
if ((err = chacha_setup(&state->chacha, key,
|
||||
CHACHA20_KEY_LEN, 20)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = chacha_setup(&state->header, key + CHACHA20_KEY_LEN,
|
||||
CHACHA20_KEY_LEN, 20) != CRYPT_OK)) {
|
||||
return err;
|
||||
}
|
||||
|
||||
TRACE2(("leave dropbear_chachapoly_start"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int dropbear_chachapoly_crypt(unsigned int seq,
|
||||
const unsigned char *in, unsigned char *out,
|
||||
unsigned long len, unsigned long taglen,
|
||||
dropbear_chachapoly_state *state, int direction) {
|
||||
poly1305_state poly;
|
||||
unsigned char seqbuf[8], key[POLY1305_KEY_LEN], tag[POLY1305_TAG_LEN];
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_chachapoly_crypt"))
|
||||
|
||||
if (len < 4 || taglen != POLY1305_TAG_LEN) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
STORE64H((uint64_t)seq, seqbuf);
|
||||
chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 0);
|
||||
if ((err = chacha_keystream(&state->chacha, key, sizeof(key))) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
poly1305_init(&poly, key, sizeof(key));
|
||||
if (direction == LTC_DECRYPT) {
|
||||
poly1305_process(&poly, in, len);
|
||||
poly1305_done(&poly, tag, &taglen);
|
||||
if (constant_time_memcmp(in + len, tag, taglen) != 0) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0);
|
||||
if ((err = chacha_crypt(&state->header, in, 4, out)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 1);
|
||||
if ((err = chacha_crypt(&state->chacha, in + 4, len - 4, out + 4)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (direction == LTC_ENCRYPT) {
|
||||
poly1305_process(&poly, out, len);
|
||||
poly1305_done(&poly, out + len, &taglen);
|
||||
}
|
||||
|
||||
TRACE2(("leave dropbear_chachapoly_crypt"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int dropbear_chachapoly_getlength(unsigned int seq,
|
||||
const unsigned char *in, unsigned int *outlen,
|
||||
unsigned long len, dropbear_chachapoly_state *state) {
|
||||
unsigned char seqbuf[8], buf[4];
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_chachapoly_getlength"))
|
||||
|
||||
if (len < sizeof(buf)) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
STORE64H((uint64_t)seq, seqbuf);
|
||||
chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0);
|
||||
if ((err = chacha_crypt(&state->header, in, sizeof(buf), buf)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
LOAD32H(*outlen, buf);
|
||||
|
||||
TRACE2(("leave dropbear_chachapoly_getlength"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
const struct dropbear_cipher_mode dropbear_mode_chachapoly =
|
||||
{(void *)dropbear_chachapoly_start, NULL, NULL,
|
||||
(void *)dropbear_chachapoly_crypt,
|
||||
(void *)dropbear_chachapoly_getlength, &dropbear_chachapoly_mac};
|
||||
|
||||
#endif /* DROPBEAR_CHACHA20POLY1305 */
|
||||
44
chachapoly.h
Normal file
44
chachapoly.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2020 by Vladislav Grishenko
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef DROPBEAR_DROPBEAR_CHACHAPOLY_H_
|
||||
#define DROPBEAR_DROPBEAR_CHACHAPOLY_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
|
||||
#if DROPBEAR_CHACHA20POLY1305
|
||||
|
||||
typedef struct {
|
||||
chacha_state chacha;
|
||||
chacha_state header;
|
||||
} dropbear_chachapoly_state;
|
||||
|
||||
extern const struct dropbear_cipher dropbear_chachapoly;
|
||||
extern const struct dropbear_cipher_mode dropbear_mode_chachapoly;
|
||||
|
||||
#endif /* DROPBEAR_CHACHA20POLY1305 */
|
||||
|
||||
#endif /* DROPBEAR_DROPBEAR_CHACHAPOLY_H_ */
|
||||
@@ -41,6 +41,9 @@ struct ChanSess {
|
||||
|
||||
char * cmd; /* command to exec */
|
||||
pid_t pid; /* child process pid */
|
||||
/* command that was sent by the client, if authorized_keys command= or
|
||||
dropbear -c was used */
|
||||
char *original_command;
|
||||
|
||||
/* pty details */
|
||||
int master; /* the master terminal fd*/
|
||||
@@ -72,10 +75,6 @@ struct ChanSess {
|
||||
char * agentfile;
|
||||
char * agentdir;
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
|
||||
char *original_command;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ChildPid {
|
||||
|
||||
@@ -255,11 +255,12 @@ void cli_load_agent_keys(m_list *ret_list) {
|
||||
}
|
||||
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const buffer *data_buf) {
|
||||
const buffer *data_buf, enum signature_type sigtype) {
|
||||
buffer *request_data = NULL;
|
||||
buffer *response = NULL;
|
||||
unsigned int siglen;
|
||||
int packet_type;
|
||||
int flags = 0;
|
||||
|
||||
/* Request format
|
||||
byte SSH2_AGENTC_SIGN_REQUEST
|
||||
@@ -271,7 +272,12 @@ void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
buf_put_pub_key(request_data, key, key->type);
|
||||
|
||||
buf_putbufstring(request_data, data_buf);
|
||||
buf_putint(request_data, 0);
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) {
|
||||
flags |= SSH_AGENT_RSA_SHA2_256;
|
||||
}
|
||||
#endif
|
||||
buf_putint(request_data, flags);
|
||||
|
||||
response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
|
||||
|
||||
|
||||
100
cli-authpubkey.c
100
cli-authpubkey.c
@@ -33,7 +33,7 @@
|
||||
#include "agentfwd.h"
|
||||
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
|
||||
static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype, int realsign);
|
||||
|
||||
/* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request.
|
||||
* We use it to remove the key we tried from the list */
|
||||
@@ -59,13 +59,15 @@ void recv_msg_userauth_pk_ok() {
|
||||
char* algotype = NULL;
|
||||
unsigned int algolen;
|
||||
enum signkey_type keytype;
|
||||
enum signature_type sigtype;
|
||||
unsigned int remotelen;
|
||||
|
||||
TRACE(("enter recv_msg_userauth_pk_ok"))
|
||||
|
||||
algotype = buf_getstring(ses.payload, &algolen);
|
||||
keytype = signkey_type_from_name(algotype, algolen);
|
||||
TRACE(("recv_msg_userauth_pk_ok: type %d", keytype))
|
||||
sigtype = signature_type_from_name(algotype, algolen);
|
||||
keytype = signkey_type_from_signature(sigtype);
|
||||
TRACE(("recv_msg_userauth_pk_ok: type %d", sigtype))
|
||||
m_free(algotype);
|
||||
|
||||
keybuf = buf_new(MAX_PUBKEY_SIZE);
|
||||
@@ -112,7 +114,7 @@ void recv_msg_userauth_pk_ok() {
|
||||
TRACE(("matching key"))
|
||||
/* XXX TODO: if it's an encrypted key, here we ask for their
|
||||
* password */
|
||||
send_msg_userauth_pubkey((sign_key*)iter->item, keytype, 1);
|
||||
send_msg_userauth_pubkey((sign_key*)iter->item, sigtype, 1);
|
||||
} else {
|
||||
TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part"))
|
||||
}
|
||||
@@ -120,31 +122,32 @@ void recv_msg_userauth_pk_ok() {
|
||||
TRACE(("leave recv_msg_userauth_pk_ok"))
|
||||
}
|
||||
|
||||
void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
static void cli_buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype,
|
||||
const buffer *data_buf) {
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
// TODO: rsa-sha256 agent
|
||||
if (key->source == SIGNKEY_SOURCE_AGENT) {
|
||||
/* Format the agent signature ourselves, as buf_put_sign would. */
|
||||
buffer *sigblob;
|
||||
sigblob = buf_new(MAX_PUBKEY_SIZE);
|
||||
agent_buf_sign(sigblob, key, data_buf);
|
||||
agent_buf_sign(sigblob, key, data_buf, sigtype);
|
||||
buf_putbufstring(buf, sigblob);
|
||||
buf_free(sigblob);
|
||||
} else
|
||||
#endif /* DROPBEAR_CLI_AGENTFWD */
|
||||
{
|
||||
buf_put_sign(buf, key, type, data_buf);
|
||||
buf_put_sign(buf, key, sigtype, data_buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: make it take an agent reference to use as well */
|
||||
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype, int realsign) {
|
||||
|
||||
const char *algoname = NULL;
|
||||
unsigned int algolen;
|
||||
buffer* sigbuf = NULL;
|
||||
enum signkey_type keytype = signkey_type_from_signature(sigtype);
|
||||
|
||||
TRACE(("enter send_msg_userauth_pubkey"))
|
||||
TRACE(("enter send_msg_userauth_pubkey sigtype %d", sigtype))
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
|
||||
@@ -160,10 +163,9 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
|
||||
buf_putbyte(ses.writepayload, realsign);
|
||||
|
||||
algoname = signkey_name_from_type(type, &algolen);
|
||||
|
||||
algoname = signature_name_from_type(sigtype, &algolen);
|
||||
buf_putstring(ses.writepayload, algoname, algolen);
|
||||
buf_put_pub_key(ses.writepayload, key, type);
|
||||
buf_put_pub_key(ses.writepayload, key, keytype);
|
||||
|
||||
if (realsign) {
|
||||
TRACE(("realsign"))
|
||||
@@ -172,7 +174,7 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
sigbuf = buf_new(4 + ses.session_id->len + ses.writepayload->len);
|
||||
buf_putbufstring(sigbuf, ses.session_id);
|
||||
buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
|
||||
cli_buf_put_sign(ses.writepayload, key, type, sigbuf);
|
||||
cli_buf_put_sign(ses.writepayload, key, sigtype, sigbuf);
|
||||
buf_free(sigbuf); /* Nothing confidential in the buffer */
|
||||
}
|
||||
|
||||
@@ -182,7 +184,7 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
|
||||
/* Returns 1 if a key was tried */
|
||||
int cli_auth_pubkey() {
|
||||
|
||||
enum signature_type sigtype = DROPBEAR_SIGNATURE_NONE;
|
||||
TRACE(("enter cli_auth_pubkey"))
|
||||
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
@@ -190,13 +192,79 @@ int cli_auth_pubkey() {
|
||||
/* get the list of available keys from the agent */
|
||||
cli_load_agent_keys(cli_opts.privkeys);
|
||||
cli_opts.agent_keys_loaded = 1;
|
||||
TRACE(("cli_auth_pubkey: agent keys loaded"))
|
||||
}
|
||||
#endif
|
||||
|
||||
/* iterate through privkeys to remove ones not allowed in server-sig-algs */
|
||||
while (cli_opts.privkeys->first) {
|
||||
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
|
||||
if (cli_ses.server_sig_algs) {
|
||||
#if DROPBEAR_RSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA) {
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNATURE_RSA_SHA256)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
|
||||
TRACE(("server-sig-algs allows rsa sha256"))
|
||||
break;
|
||||
}
|
||||
#endif /* DROPBEAR_RSA_SHA256 */
|
||||
#if DROPBEAR_RSA_SHA1
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNKEY_RSA)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
TRACE(("server-sig-algs allows rsa sha1"))
|
||||
break;
|
||||
}
|
||||
#endif /* DROPBEAR_RSA_SHA256 */
|
||||
} else
|
||||
#endif /* DROPBEAR_RSA */
|
||||
{
|
||||
/* Not RSA */
|
||||
const char *name = NULL;
|
||||
sigtype = signature_type_from_signkey(key->type);
|
||||
name = signature_name_from_type(sigtype, NULL);
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, name)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
TRACE(("server-sig-algs allows %s", name))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* No match, skip this key */
|
||||
TRACE(("server-sig-algs no match keytype %d, skipping", key->type))
|
||||
key = list_remove(cli_opts.privkeys->first);
|
||||
sign_key_free(key);
|
||||
continue;
|
||||
} else {
|
||||
/* Server didn't provide a server-sig-algs list, we'll
|
||||
assume all except rsa-sha256 are OK. */
|
||||
#if DROPBEAR_RSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA) {
|
||||
#if DROPBEAR_RSA_SHA1
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
TRACE(("no server-sig-algs, using rsa sha1"))
|
||||
break;
|
||||
#else
|
||||
/* only support rsa-sha256, skip this key */
|
||||
TRACE(("no server-sig-algs, skipping rsa sha256"))
|
||||
key = list_remove(cli_opts.privkeys->first);
|
||||
sign_key_free(key);
|
||||
continue;
|
||||
#endif
|
||||
} /* key->type == DROPBEAR_SIGNKEY_RSA */
|
||||
#endif /* DROPBEAR_RSA */
|
||||
sigtype = signature_type_from_signkey(key->type);
|
||||
TRACE(("no server-sig-algs, using key"))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cli_opts.privkeys->first) {
|
||||
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
|
||||
/* Send a trial request */
|
||||
send_msg_userauth_pubkey(key, key->type, 0);
|
||||
send_msg_userauth_pubkey(key, sigtype, 0);
|
||||
cli_ses.lastprivkey = key;
|
||||
TRACE(("leave cli_auth_pubkey-success"))
|
||||
return 1;
|
||||
|
||||
50
cli-kex.c
50
cli-kex.c
@@ -81,7 +81,7 @@ void send_msg_kexdh_init() {
|
||||
}
|
||||
cli_ses.curve25519_param = gen_kexcurve25519_param();
|
||||
}
|
||||
buf_putstring(ses.writepayload, (const char*)cli_ses.curve25519_param->pub, CURVE25519_LEN);
|
||||
buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
@@ -94,7 +94,7 @@ void send_msg_kexdh_init() {
|
||||
void recv_msg_kexdh_reply() {
|
||||
|
||||
sign_key *hostkey = NULL;
|
||||
unsigned int type, keybloblen;
|
||||
unsigned int keytype, keybloblen;
|
||||
unsigned char* keyblob = NULL;
|
||||
|
||||
TRACE(("enter recv_msg_kexdh_reply"))
|
||||
@@ -102,8 +102,8 @@ void recv_msg_kexdh_reply() {
|
||||
if (cli_ses.kex_state != KEXDH_INIT_SENT) {
|
||||
dropbear_exit("Received out-of-order kexdhreply");
|
||||
}
|
||||
type = ses.newkeys->algo_hostkey;
|
||||
TRACE(("type is %d", type))
|
||||
keytype = ses.newkeys->algo_hostkey;
|
||||
TRACE(("keytype is %d", keytype))
|
||||
|
||||
hostkey = new_sign_key();
|
||||
keybloblen = buf_getint(ses.payload);
|
||||
@@ -114,7 +114,7 @@ void recv_msg_kexdh_reply() {
|
||||
checkhostkey(keyblob, keybloblen);
|
||||
}
|
||||
|
||||
if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) {
|
||||
if (buf_get_pub_key(ses.payload, hostkey, &keytype) != DROPBEAR_SUCCESS) {
|
||||
TRACE(("failed getting pubkey"))
|
||||
dropbear_exit("Bad KEX packet");
|
||||
}
|
||||
@@ -155,10 +155,12 @@ void recv_msg_kexdh_reply() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
if (cli_ses.dh_param) {
|
||||
free_kexdh_param(cli_ses.dh_param);
|
||||
cli_ses.dh_param = NULL;
|
||||
}
|
||||
#endif
|
||||
#if DROPBEAR_ECDH
|
||||
if (cli_ses.ecdh_param) {
|
||||
free_kexecdh_param(cli_ses.ecdh_param);
|
||||
@@ -173,7 +175,8 @@ void recv_msg_kexdh_reply() {
|
||||
#endif
|
||||
|
||||
cli_ses.param_kex_algo = NULL;
|
||||
if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) {
|
||||
if (buf_verify(ses.payload, hostkey, ses.newkeys->algo_signature,
|
||||
ses.hash) != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Bad hostkey signature");
|
||||
}
|
||||
|
||||
@@ -410,3 +413,38 @@ out:
|
||||
}
|
||||
m_free(fingerprint);
|
||||
}
|
||||
|
||||
void recv_msg_ext_info(void) {
|
||||
/* This message is not client-specific in the protocol but Dropbear only handles
|
||||
a server-sent message at present. */
|
||||
unsigned int num_ext;
|
||||
unsigned int i;
|
||||
|
||||
TRACE(("enter recv_msg_ext_info"))
|
||||
|
||||
/* Must be after the first SSH_MSG_NEWKEYS */
|
||||
TRACE(("last %d, donefirst %d, donescond %d", ses.lastpacket, ses.kexstate.donefirstkex, ses.kexstate.donesecondkex))
|
||||
if (!(ses.lastpacket == SSH_MSG_NEWKEYS && !ses.kexstate.donesecondkex)) {
|
||||
TRACE(("leave recv_msg_ext_info: ignoring packet received at the wrong time"))
|
||||
return;
|
||||
}
|
||||
|
||||
num_ext = buf_getint(ses.payload);
|
||||
TRACE(("received SSH_MSG_EXT_INFO with %d items", num_ext))
|
||||
|
||||
for (i = 0; i < num_ext; i++) {
|
||||
unsigned int name_len;
|
||||
char *ext_name = buf_getstring(ses.payload, &name_len);
|
||||
TRACE(("extension %d name '%s'", i, ext_name))
|
||||
if (cli_ses.server_sig_algs == NULL
|
||||
&& name_len == strlen(SSH_SERVER_SIG_ALGS)
|
||||
&& strcmp(ext_name, SSH_SERVER_SIG_ALGS) == 0) {
|
||||
cli_ses.server_sig_algs = buf_getbuf(ses.payload);
|
||||
} else {
|
||||
/* valid extension values could be >MAX_STRING_LEN */
|
||||
buf_eatstring(ses.payload);
|
||||
}
|
||||
m_free(ext_name);
|
||||
}
|
||||
TRACE(("leave recv_msg_ext_info"))
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
|
||||
|
||||
/* Render the formatted exit message */
|
||||
vsnprintf(exitmsg, sizeof(exitmsg), format, param);
|
||||
TRACE(("Exited, cleaning up: %s", exitmsg))
|
||||
|
||||
/* Add the prefix depending on session/auth state */
|
||||
if (!ses.init_done) {
|
||||
@@ -130,6 +131,12 @@ static void cli_dropbear_log(int priority,
|
||||
const char* format, va_list param) {
|
||||
|
||||
char printbuf[1024];
|
||||
const char *name;
|
||||
|
||||
name = cli_opts.progname;
|
||||
if (!name) {
|
||||
name = "dbclient";
|
||||
}
|
||||
|
||||
vsnprintf(printbuf, sizeof(printbuf), format, param);
|
||||
|
||||
@@ -139,7 +146,7 @@ static void cli_dropbear_log(int priority,
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf);
|
||||
fprintf(stderr, "%s: %s\n", name, printbuf);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
||||
@@ -378,6 +378,11 @@ void cli_getopts(int argc, char ** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
/* -c help doesn't need a hostname */
|
||||
parse_ciphers_macs();
|
||||
#endif
|
||||
|
||||
/* Done with options/flags; now handle the hostname (which may not
|
||||
* start with a hyphen) and optional command */
|
||||
|
||||
@@ -408,10 +413,6 @@ void cli_getopts(int argc, char ** argv) {
|
||||
|
||||
/* And now a few sanity checks and setup */
|
||||
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
parse_ciphers_macs();
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_CLI_PROXYCMD
|
||||
if (cli_opts.proxycmd) {
|
||||
/* To match the common path of m_freeing it */
|
||||
|
||||
@@ -81,6 +81,7 @@ static const packettype cli_packettypes[] = {
|
||||
{SSH_MSG_REQUEST_SUCCESS, ignore_recv_response},
|
||||
{SSH_MSG_REQUEST_FAILURE, ignore_recv_response},
|
||||
#endif
|
||||
{SSH_MSG_EXT_INFO, recv_msg_ext_info},
|
||||
{0, NULL} /* End */
|
||||
};
|
||||
|
||||
@@ -352,11 +353,13 @@ static void cli_session_cleanup(void) {
|
||||
(void)fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags);
|
||||
|
||||
cli_tty_cleanup();
|
||||
|
||||
if (cli_ses.server_sig_algs) {
|
||||
buf_free(cli_ses.server_sig_algs);
|
||||
}
|
||||
}
|
||||
|
||||
static void cli_finished() {
|
||||
TRACE(("cli_finised()"))
|
||||
TRACE(("cli_finished()"))
|
||||
|
||||
session_cleanup();
|
||||
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
|
||||
|
||||
238
common-algo.c
238
common-algo.c
@@ -30,6 +30,9 @@
|
||||
#include "dh_groups.h"
|
||||
#include "ltc_prng.h"
|
||||
#include "ecc.h"
|
||||
#include "gcm.h"
|
||||
#include "chachapoly.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/* This file (algo.c) organises the ciphers which can be used, and is used to
|
||||
* decide which ciphers/hashes/compression/signing to use during key exchange*/
|
||||
@@ -61,10 +64,6 @@ static const struct dropbear_cipher dropbear_aes256 =
|
||||
static const struct dropbear_cipher dropbear_aes128 =
|
||||
{&aes_desc, 16, 16};
|
||||
#endif
|
||||
#if DROPBEAR_BLOWFISH
|
||||
static const struct dropbear_cipher dropbear_blowfish =
|
||||
{&blowfish_desc, 16, 8};
|
||||
#endif
|
||||
#if DROPBEAR_TWOFISH256
|
||||
static const struct dropbear_cipher dropbear_twofish256 =
|
||||
{&twofish_desc, 32, 16};
|
||||
@@ -86,11 +85,11 @@ const struct dropbear_cipher dropbear_nocipher =
|
||||
* about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
const struct dropbear_cipher_mode dropbear_mode_cbc =
|
||||
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
|
||||
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt, NULL, NULL, NULL};
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
|
||||
const struct dropbear_cipher_mode dropbear_mode_none =
|
||||
{void_start, void_cipher, void_cipher};
|
||||
{void_start, void_cipher, void_cipher, NULL, NULL, NULL};
|
||||
|
||||
#if DROPBEAR_ENABLE_CTR_MODE
|
||||
/* a wrapper to make ctr_start and cbc_start look the same */
|
||||
@@ -101,7 +100,7 @@ static int dropbear_big_endian_ctr_start(int cipher,
|
||||
return ctr_start(cipher, IV, key, keylen, num_rounds, CTR_COUNTER_BIG_ENDIAN, ctr);
|
||||
}
|
||||
const struct dropbear_cipher_mode dropbear_mode_ctr =
|
||||
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
|
||||
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt, NULL, NULL, NULL};
|
||||
#endif /* DROPBEAR_ENABLE_CTR_MODE */
|
||||
|
||||
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
|
||||
@@ -137,6 +136,19 @@ const struct dropbear_hash dropbear_nohash =
|
||||
* that is also supported by the server will get used. */
|
||||
|
||||
algo_type sshciphers[] = {
|
||||
#if DROPBEAR_CHACHA20POLY1305
|
||||
{"chacha20-poly1305@openssh.com", 0, &dropbear_chachapoly, 1, &dropbear_mode_chachapoly},
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_ENABLE_GCM_MODE
|
||||
#if DROPBEAR_AES128
|
||||
{"aes128-gcm@openssh.com", 0, &dropbear_aes128, 1, &dropbear_mode_gcm},
|
||||
#endif
|
||||
#if DROPBEAR_AES256
|
||||
{"aes256-gcm@openssh.com", 0, &dropbear_aes256, 1, &dropbear_mode_gcm},
|
||||
#endif
|
||||
#endif /* DROPBEAR_ENABLE_GCM_MODE */
|
||||
|
||||
#if DROPBEAR_ENABLE_CTR_MODE
|
||||
#if DROPBEAR_AES128
|
||||
{"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
|
||||
@@ -169,15 +181,18 @@ algo_type sshciphers[] = {
|
||||
#if DROPBEAR_TWOFISH128
|
||||
{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
|
||||
#if DROPBEAR_3DES
|
||||
#if DROPBEAR_ENABLE_CTR_MODE
|
||||
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#if DROPBEAR_3DES
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#if DROPBEAR_BLOWFISH
|
||||
{"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#endif /* DROPBEAR_3DES */
|
||||
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
@@ -221,23 +236,31 @@ algo_type ssh_nocompress[] = {
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
algo_type sshhostkey[] = {
|
||||
algo_type sigalgs[] = {
|
||||
#if DROPBEAR_ED25519
|
||||
{"ssh-ed25519", DROPBEAR_SIGNATURE_ED25519, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_ECDSA
|
||||
#if DROPBEAR_ECC_256
|
||||
{"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL},
|
||||
{"ecdsa-sha2-nistp256", DROPBEAR_SIGNATURE_ECDSA_NISTP256, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_ECC_384
|
||||
{"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL},
|
||||
{"ecdsa-sha2-nistp384", DROPBEAR_SIGNATURE_ECDSA_NISTP384, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_ECC_521
|
||||
{"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL},
|
||||
{"ecdsa-sha2-nistp521", DROPBEAR_SIGNATURE_ECDSA_NISTP521, NULL, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
#if DROPBEAR_RSA
|
||||
{"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL},
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
{"rsa-sha2-256", DROPBEAR_SIGNATURE_RSA_SHA256, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_RSA_SHA1
|
||||
{"ssh-rsa", DROPBEAR_SIGNATURE_RSA_SHA1, NULL, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
#if DROPBEAR_DSS
|
||||
{"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1, NULL},
|
||||
{"ssh-dss", DROPBEAR_SIGNATURE_DSS, NULL, 1, NULL},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
@@ -255,8 +278,6 @@ static const struct dropbear_kex kex_dh_group14_sha256 = {DROPBEAR_KEX_NORMAL_DH
|
||||
static const struct dropbear_kex kex_dh_group16_sha512 = {DROPBEAR_KEX_NORMAL_DH, dh_p_16, DH_P_16_LEN, NULL, &sha512_desc };
|
||||
#endif
|
||||
|
||||
/* These can't be const since dropbear_ecc_fill_dp() fills out
|
||||
ecc_curve at runtime */
|
||||
#if DROPBEAR_ECDH
|
||||
#if DROPBEAR_ECC_256
|
||||
static const struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
|
||||
@@ -274,6 +295,7 @@ static const struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0
|
||||
static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc };
|
||||
#endif
|
||||
|
||||
/* data == NULL for non-kex algorithm identifiers */
|
||||
algo_type sshkex[] = {
|
||||
#if DROPBEAR_CURVE25519
|
||||
{"curve25519-sha256", 0, &kex_curve25519, 1, NULL},
|
||||
@@ -303,49 +325,122 @@ algo_type sshkex[] = {
|
||||
{"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_KEXGUESS2
|
||||
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
|
||||
{KEXGUESS2_ALGO_NAME, 0, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_EXT_INFO
|
||||
#if DROPBEAR_CLIENT
|
||||
/* Set unusable by svr_algos_initialise() */
|
||||
{SSH_EXT_INFO_C, 0, NULL, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
/* algolen specifies the length of algo, algos is our local list to match
|
||||
* against.
|
||||
* Returns DROPBEAR_SUCCESS if we have a match for algo, DROPBEAR_FAILURE
|
||||
* otherwise */
|
||||
int have_algo(const char* algo, size_t algolen, const algo_type algos[]) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; algos[i].name != NULL; i++) {
|
||||
if (strlen(algos[i].name) == algolen
|
||||
&& (strncmp(algos[i].name, algo, algolen) == 0)) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* Output a comma separated list of algorithms to a buffer */
|
||||
void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
|
||||
|
||||
void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall) {
|
||||
unsigned int i, len;
|
||||
unsigned int donefirst = 0;
|
||||
buffer *algolist = NULL;
|
||||
unsigned int startpos;
|
||||
|
||||
algolist = buf_new(300);
|
||||
startpos = buf->pos;
|
||||
/* Placeholder for length */
|
||||
buf_putint(buf, 0);
|
||||
for (i = 0; localalgos[i].name != NULL; i++) {
|
||||
if (localalgos[i].usable) {
|
||||
if (donefirst)
|
||||
buf_putbyte(algolist, ',');
|
||||
if (localalgos[i].usable || useall) {
|
||||
if (donefirst) {
|
||||
buf_putbyte(buf, ',');
|
||||
}
|
||||
donefirst = 1;
|
||||
len = strlen(localalgos[i].name);
|
||||
buf_putbytes(algolist, (const unsigned char *) localalgos[i].name, len);
|
||||
buf_putbytes(buf, (const unsigned char *) localalgos[i].name, len);
|
||||
}
|
||||
}
|
||||
buf_putstring(buf, (const char*)algolist->data, algolist->len);
|
||||
TRACE(("algolist add '%*s'", algolist->len, algolist->data))
|
||||
buf_free(algolist);
|
||||
/* Fill out the length */
|
||||
len = buf->pos - startpos - 4;
|
||||
buf_setpos(buf, startpos);
|
||||
buf_putint(buf, len);
|
||||
TRACE(("algolist add %d '%*s'", len, len, buf_getptr(buf, len)))
|
||||
buf_incrwritepos(buf, len);
|
||||
}
|
||||
|
||||
void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
|
||||
buf_put_algolist_all(buf, localalgos, 0);
|
||||
}
|
||||
|
||||
/* returns a list of pointers into algolist, of null-terminated names.
|
||||
ret_list should be passed in with space for *ret_count elements,
|
||||
on return *ret_count has the number of names filled.
|
||||
algolist is modified. */
|
||||
static void get_algolist(char* algolist, unsigned int algolist_len,
|
||||
const char* *ret_list, unsigned int *ret_count) {
|
||||
unsigned int max_count = *ret_count;
|
||||
unsigned int i;
|
||||
|
||||
if (*ret_count == 0) {
|
||||
return;
|
||||
}
|
||||
if (algolist_len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
*ret_count = 0;
|
||||
}
|
||||
|
||||
/* ret_list will contain a list of the strings parsed out.
|
||||
We will have at least one string (even if it's just "") */
|
||||
ret_list[0] = algolist;
|
||||
*ret_count = 1;
|
||||
for (i = 0; i < algolist_len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
*ret_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (algolist[i] == ',') {
|
||||
if (*ret_count >= max_count) {
|
||||
/* Too many */
|
||||
*ret_count = 0;
|
||||
return;
|
||||
}
|
||||
algolist[i] = '\0';
|
||||
ret_list[*ret_count] = &algolist[i+1];
|
||||
(*ret_count)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return DROPBEAR_SUCCESS if the namelist contains algo,
|
||||
DROPBEAR_FAILURE otherwise. buf position is not incremented. */
|
||||
int buf_has_algo(buffer *buf, const char *algo) {
|
||||
unsigned char* algolist = NULL;
|
||||
unsigned int orig_pos = buf->pos;
|
||||
unsigned int len, remotecount, i;
|
||||
const char *remotenames[MAX_PROPOSED_ALGO];
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
algolist = buf_getstring(buf, &len);
|
||||
remotecount = MAX_PROPOSED_ALGO;
|
||||
get_algolist(algolist, len, remotenames, &remotecount);
|
||||
for (i = 0; i < remotecount; i++)
|
||||
{
|
||||
if (strcmp(remotenames[i], algo) == 0) {
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (algolist) {
|
||||
m_free(algolist);
|
||||
}
|
||||
buf_setpos(buf, orig_pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
algo_type * first_usable_algo(algo_type algos[]) {
|
||||
int i;
|
||||
for (i = 0; algos[i].name != NULL; i++) {
|
||||
if (algos[i].usable) {
|
||||
return &algos[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* match the first algorithm in the comma-separated list in buf which is
|
||||
@@ -354,9 +449,7 @@ void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
|
||||
* 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
|
||||
* guessed correctly */
|
||||
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
enum kexguess2_used *kexguess2, int *goodguess)
|
||||
{
|
||||
|
||||
int kexguess2, int *goodguess) {
|
||||
char * algolist = NULL;
|
||||
const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
@@ -371,40 +464,8 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
|
||||
algolist = buf_getstring(buf, &len);
|
||||
TRACE(("buf_match_algo: %s", algolist))
|
||||
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* remotenames will contain a list of the strings parsed out */
|
||||
/* We will have at least one string (even if it's just "") */
|
||||
remotenames[0] = algolist;
|
||||
remotecount = 1;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
goto out;
|
||||
}
|
||||
if (algolist[i] == ',') {
|
||||
algolist[i] = '\0';
|
||||
remotenames[remotecount] = &algolist[i+1];
|
||||
remotecount++;
|
||||
}
|
||||
if (remotecount >= MAX_PROPOSED_ALGO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) {
|
||||
for (i = 0; i < remotecount; i++)
|
||||
{
|
||||
if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) {
|
||||
*kexguess2 = KEXGUESS2_YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*kexguess2 == KEXGUESS2_LOOK) {
|
||||
*kexguess2 = KEXGUESS2_NO;
|
||||
}
|
||||
}
|
||||
remotecount = MAX_PROPOSED_ALGO;
|
||||
get_algolist(algolist, len, remotenames, &remotecount);
|
||||
|
||||
for (i = 0; localalgos[i].name != NULL; i++) {
|
||||
if (localalgos[i].usable) {
|
||||
@@ -436,12 +497,11 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
}
|
||||
if (strcmp(servnames[j], clinames[i]) == 0) {
|
||||
/* set if it was a good guess */
|
||||
if (goodguess && kexguess2) {
|
||||
if (*kexguess2 == KEXGUESS2_YES) {
|
||||
if (goodguess != NULL) {
|
||||
if (kexguess2) {
|
||||
if (i == 0) {
|
||||
*goodguess = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (i == 0 && j == 0) {
|
||||
*goodguess = 1;
|
||||
|
||||
129
common-kex.c
129
common-kex.c
@@ -36,6 +36,7 @@
|
||||
#include "dbrandom.h"
|
||||
#include "runopts.h"
|
||||
#include "ecc.h"
|
||||
#include "curve25519.h"
|
||||
#include "crypto_desc.h"
|
||||
|
||||
static void kexinitialise(void);
|
||||
@@ -64,7 +65,7 @@ void send_msg_kexinit() {
|
||||
buf_put_algolist(ses.writepayload, sshkex);
|
||||
|
||||
/* server_host_key_algorithms */
|
||||
buf_put_algolist(ses.writepayload, sshhostkey);
|
||||
buf_put_algolist(ses.writepayload, sigalgs);
|
||||
|
||||
/* encryption_algorithms_client_to_server */
|
||||
buf_put_algolist(ses.writepayload, sshciphers);
|
||||
@@ -109,8 +110,9 @@ void send_msg_kexinit() {
|
||||
ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
|
||||
if (ses.send_kex_first_guess) {
|
||||
ses.newkeys->algo_kex = sshkex[0].data;
|
||||
ses.newkeys->algo_hostkey = sshhostkey[0].val;
|
||||
ses.newkeys->algo_kex = first_usable_algo(sshkex)->data;
|
||||
ses.newkeys->algo_signature = first_usable_algo(sigalgs)->val;
|
||||
ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature);
|
||||
ses.send_kex_first_guess();
|
||||
}
|
||||
|
||||
@@ -151,6 +153,7 @@ static void switch_keys() {
|
||||
TRACE(("switch_keys done"))
|
||||
ses.keys->algo_kex = ses.newkeys->algo_kex;
|
||||
ses.keys->algo_hostkey = ses.newkeys->algo_hostkey;
|
||||
ses.keys->algo_signature = ses.newkeys->algo_signature;
|
||||
ses.keys->allow_compress = 0;
|
||||
m_free(ses.newkeys);
|
||||
ses.newkeys = NULL;
|
||||
@@ -172,6 +175,9 @@ void send_msg_newkeys() {
|
||||
|
||||
/* set up our state */
|
||||
ses.kexstate.sentnewkeys = 1;
|
||||
if (ses.kexstate.donefirstkex) {
|
||||
ses.kexstate.donesecondkex = 1;
|
||||
}
|
||||
ses.kexstate.donefirstkex = 1;
|
||||
ses.dataallowed = 1; /* we can send other packets again now */
|
||||
gen_new_keys();
|
||||
@@ -194,8 +200,6 @@ void recv_msg_newkeys() {
|
||||
|
||||
/* Set up the kex for the first time */
|
||||
void kexfirstinitialise() {
|
||||
ses.kexstate.donefirstkex = 0;
|
||||
|
||||
#ifdef DISABLE_ZLIB
|
||||
ses.compress_algos = ssh_nocompress;
|
||||
#else
|
||||
@@ -328,9 +332,13 @@ static void gen_new_keys() {
|
||||
hashkeys(S2C_key, sizeof(S2C_key), &hs, 'D');
|
||||
|
||||
if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) {
|
||||
int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
|
||||
if (recv_cipher < 0)
|
||||
dropbear_exit("Crypto error");
|
||||
int recv_cipher = -1;
|
||||
if (ses.newkeys->recv.algo_crypt->cipherdesc->name != NULL) {
|
||||
recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
|
||||
if (recv_cipher < 0) {
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
}
|
||||
if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
|
||||
recv_IV, recv_key,
|
||||
ses.newkeys->recv.algo_crypt->keysize, 0,
|
||||
@@ -340,9 +348,13 @@ static void gen_new_keys() {
|
||||
}
|
||||
|
||||
if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) {
|
||||
int trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
|
||||
if (trans_cipher < 0)
|
||||
dropbear_exit("Crypto error");
|
||||
int trans_cipher = -1;
|
||||
if (ses.newkeys->trans.algo_crypt->cipherdesc->name != NULL) {
|
||||
trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
|
||||
if (trans_cipher < 0) {
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
}
|
||||
if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
|
||||
trans_IV, trans_key,
|
||||
ses.newkeys->trans.algo_crypt->keysize, 0,
|
||||
@@ -536,6 +548,7 @@ void recv_msg_kexinit() {
|
||||
TRACE(("leave recv_msg_kexinit"))
|
||||
}
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
static void load_dh_p(mp_int * dh_p)
|
||||
{
|
||||
bytes_to_mp(dh_p, ses.newkeys->algo_kex->dh_p_bytes,
|
||||
@@ -560,9 +573,7 @@ struct kex_dh_param *gen_kexdh_param() {
|
||||
/* read the prime and generator*/
|
||||
load_dh_p(&dh_p);
|
||||
|
||||
if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
mp_set_ul(&dh_g, DH_G_VAL);
|
||||
|
||||
/* calculate q = (p-1)/2 */
|
||||
/* dh_priv is just a temp var here */
|
||||
@@ -646,6 +657,7 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
|
||||
/* calculate the hash H to sign */
|
||||
finish_kexhashbuf();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_ECDH
|
||||
struct kex_ecdh_param *gen_kexecdh_param() {
|
||||
@@ -703,23 +715,18 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
|
||||
#endif /* DROPBEAR_ECDH */
|
||||
|
||||
#if DROPBEAR_CURVE25519
|
||||
struct kex_curve25519_param *gen_kexcurve25519_param () {
|
||||
struct kex_curve25519_param *gen_kexcurve25519_param() {
|
||||
/* Per http://cr.yp.to/ecdh.html */
|
||||
struct kex_curve25519_param *param = m_malloc(sizeof(*param));
|
||||
const unsigned char basepoint[32] = {9};
|
||||
|
||||
genrandom(param->priv, CURVE25519_LEN);
|
||||
param->priv[0] &= 248;
|
||||
param->priv[31] &= 127;
|
||||
param->priv[31] |= 64;
|
||||
|
||||
curve25519_donna(param->pub, param->priv, basepoint);
|
||||
dropbear_curve25519_scalarmult(param->pub, param->priv, basepoint);
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
void free_kexcurve25519_param(struct kex_curve25519_param *param)
|
||||
{
|
||||
void free_kexcurve25519_param(struct kex_curve25519_param *param) {
|
||||
m_burn(param->priv, CURVE25519_LEN);
|
||||
m_free(param);
|
||||
}
|
||||
@@ -736,7 +743,7 @@ void kexcurve25519_comb_key(const struct kex_curve25519_param *param, const buff
|
||||
dropbear_exit("Bad curve25519");
|
||||
}
|
||||
|
||||
curve25519_donna(out, param->priv, buf_pub_them->data);
|
||||
dropbear_curve25519_scalarmult(out, param->priv, buf_pub_them->data);
|
||||
|
||||
if (constant_time_memcmp(zeroes, out, CURVE25519_LEN) == 0) {
|
||||
dropbear_exit("Bad curve25519");
|
||||
@@ -822,21 +829,36 @@ static void read_kex_algos() {
|
||||
int goodguess = 0;
|
||||
int allgood = 1; /* we AND this with each goodguess and see if its still
|
||||
true after */
|
||||
|
||||
#if DROPBEAR_KEXGUESS2
|
||||
enum kexguess2_used kexguess2 = KEXGUESS2_LOOK;
|
||||
#else
|
||||
enum kexguess2_used kexguess2 = KEXGUESS2_NO;
|
||||
#endif
|
||||
int kexguess2 = 0;
|
||||
|
||||
buf_incrpos(ses.payload, 16); /* start after the cookie */
|
||||
|
||||
memset(ses.newkeys, 0x0, sizeof(*ses.newkeys));
|
||||
|
||||
/* kex_algorithms */
|
||||
algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess);
|
||||
#if DROPBEAR_KEXGUESS2
|
||||
if (buf_has_algo(ses.payload, KEXGUESS2_ALGO_NAME) == DROPBEAR_SUCCESS) {
|
||||
kexguess2 = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_EXT_INFO
|
||||
/* Determine if SSH_MSG_EXT_INFO messages should be sent.
|
||||
Should be done for the first key exchange. Only required on server side
|
||||
for server-sig-algs */
|
||||
if (IS_DROPBEAR_SERVER) {
|
||||
if (!ses.kexstate.donefirstkex) {
|
||||
if (buf_has_algo(ses.payload, SSH_EXT_INFO_C) == DROPBEAR_SUCCESS) {
|
||||
ses.allow_ext_info = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
|
||||
allgood &= goodguess;
|
||||
if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) {
|
||||
if (algo == NULL || algo->data == NULL) {
|
||||
/* kexguess2, ext-info-c, ext-info-s should not match negotiation */
|
||||
erralgo = "kex";
|
||||
goto error;
|
||||
}
|
||||
@@ -845,17 +867,18 @@ static void read_kex_algos() {
|
||||
ses.newkeys->algo_kex = algo->data;
|
||||
|
||||
/* server_host_key_algorithms */
|
||||
algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
|
||||
algo = buf_match_algo(ses.payload, sigalgs, kexguess2, &goodguess);
|
||||
allgood &= goodguess;
|
||||
if (algo == NULL) {
|
||||
erralgo = "hostkey";
|
||||
goto error;
|
||||
}
|
||||
TRACE(("hostkey algo %s", algo->name))
|
||||
ses.newkeys->algo_hostkey = algo->val;
|
||||
TRACE(("signature algo %s", algo->name))
|
||||
ses.newkeys->algo_signature = algo->val;
|
||||
ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature);
|
||||
|
||||
/* encryption_algorithms_client_to_server */
|
||||
c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
|
||||
c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
|
||||
if (c2s_cipher_algo == NULL) {
|
||||
erralgo = "enc c->s";
|
||||
goto error;
|
||||
@@ -863,7 +886,7 @@ static void read_kex_algos() {
|
||||
TRACE(("enc c2s is %s", c2s_cipher_algo->name))
|
||||
|
||||
/* encryption_algorithms_server_to_client */
|
||||
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
|
||||
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
|
||||
if (s2c_cipher_algo == NULL) {
|
||||
erralgo = "enc s->c";
|
||||
goto error;
|
||||
@@ -871,23 +894,33 @@ static void read_kex_algos() {
|
||||
TRACE(("enc s2c is %s", s2c_cipher_algo->name))
|
||||
|
||||
/* mac_algorithms_client_to_server */
|
||||
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
|
||||
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
if (((struct dropbear_cipher_mode*)c2s_cipher_algo->mode)->aead_crypt != NULL) {
|
||||
c2s_hash_algo = NULL;
|
||||
} else
|
||||
#endif
|
||||
if (c2s_hash_algo == NULL) {
|
||||
erralgo = "mac c->s";
|
||||
goto error;
|
||||
}
|
||||
TRACE(("hash c2s is %s", c2s_hash_algo->name))
|
||||
TRACE(("hash c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "<implicit>"))
|
||||
|
||||
/* mac_algorithms_server_to_client */
|
||||
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
|
||||
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
if (((struct dropbear_cipher_mode*)s2c_cipher_algo->mode)->aead_crypt != NULL) {
|
||||
s2c_hash_algo = NULL;
|
||||
} else
|
||||
#endif
|
||||
if (s2c_hash_algo == NULL) {
|
||||
erralgo = "mac s->c";
|
||||
goto error;
|
||||
}
|
||||
TRACE(("hash s2c is %s", s2c_hash_algo->name))
|
||||
TRACE(("hash s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "<implicit>"))
|
||||
|
||||
/* compression_algorithms_client_to_server */
|
||||
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
|
||||
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
|
||||
if (c2s_comp_algo == NULL) {
|
||||
erralgo = "comp c->s";
|
||||
goto error;
|
||||
@@ -895,7 +928,7 @@ static void read_kex_algos() {
|
||||
TRACE(("hash c2s is %s", c2s_comp_algo->name))
|
||||
|
||||
/* compression_algorithms_server_to_client */
|
||||
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
|
||||
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
|
||||
if (s2c_comp_algo == NULL) {
|
||||
erralgo = "comp s->c";
|
||||
goto error;
|
||||
@@ -929,8 +962,14 @@ static void read_kex_algos() {
|
||||
ses.newkeys->trans.crypt_mode =
|
||||
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
|
||||
ses.newkeys->recv.algo_mac =
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
s2c_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac :
|
||||
#endif
|
||||
(struct dropbear_hash*)s2c_hash_algo->data;
|
||||
ses.newkeys->trans.algo_mac =
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
c2s_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac :
|
||||
#endif
|
||||
(struct dropbear_hash*)c2s_hash_algo->data;
|
||||
ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
|
||||
ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
|
||||
@@ -945,8 +984,14 @@ static void read_kex_algos() {
|
||||
ses.newkeys->trans.crypt_mode =
|
||||
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
|
||||
ses.newkeys->recv.algo_mac =
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
c2s_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac :
|
||||
#endif
|
||||
(struct dropbear_hash*)c2s_hash_algo->data;
|
||||
ses.newkeys->trans.algo_mac =
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
s2c_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac :
|
||||
#endif
|
||||
(struct dropbear_hash*)s2c_hash_algo->data;
|
||||
ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
|
||||
ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
|
||||
|
||||
@@ -64,45 +64,36 @@ out:
|
||||
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
void
|
||||
parse_ciphers_macs()
|
||||
{
|
||||
if (opts.cipher_list)
|
||||
{
|
||||
if (strcmp(opts.cipher_list, "help") == 0)
|
||||
{
|
||||
parse_ciphers_macs() {
|
||||
int printed_help = 0;
|
||||
if (opts.cipher_list) {
|
||||
if (strcmp(opts.cipher_list, "help") == 0) {
|
||||
char *ciphers = algolist_string(sshciphers);
|
||||
dropbear_log(LOG_INFO, "Available ciphers:\n%s\n", ciphers);
|
||||
dropbear_log(LOG_INFO, "Available ciphers: %s", ciphers);
|
||||
m_free(ciphers);
|
||||
dropbear_exit(".");
|
||||
}
|
||||
|
||||
if (strcmp(opts.cipher_list, "none") == 0)
|
||||
{
|
||||
/* Encryption is required during authentication */
|
||||
opts.cipher_list = "none,aes128-ctr";
|
||||
}
|
||||
|
||||
if (check_user_algos(opts.cipher_list, sshciphers, "cipher") == 0)
|
||||
{
|
||||
dropbear_exit("No valid ciphers specified for '-c'");
|
||||
printed_help = 1;
|
||||
} else {
|
||||
if (check_user_algos(opts.cipher_list, sshciphers, "cipher") == 0) {
|
||||
dropbear_exit("No valid ciphers specified for '-c'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.mac_list)
|
||||
{
|
||||
if (strcmp(opts.mac_list, "help") == 0)
|
||||
{
|
||||
if (opts.mac_list) {
|
||||
if (strcmp(opts.mac_list, "help") == 0) {
|
||||
char *macs = algolist_string(sshhashes);
|
||||
dropbear_log(LOG_INFO, "Available MACs:\n%s\n", macs);
|
||||
dropbear_log(LOG_INFO, "Available MACs: %s", macs);
|
||||
m_free(macs);
|
||||
dropbear_exit(".");
|
||||
}
|
||||
|
||||
if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0)
|
||||
{
|
||||
dropbear_exit("No valid MACs specified for '-m'");
|
||||
printed_help = 1;
|
||||
} else {
|
||||
if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0) {
|
||||
dropbear_exit("No valid MACs specified for '-m'");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (printed_help) {
|
||||
dropbear_exit(".");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -147,6 +147,10 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
|
||||
ses.allowprivport = 0;
|
||||
|
||||
#if DROPBEAR_PLUGIN
|
||||
ses.plugin_session = NULL;
|
||||
#endif
|
||||
|
||||
TRACE(("leave session_init"))
|
||||
}
|
||||
|
||||
@@ -366,8 +370,11 @@ static void read_session_identification() {
|
||||
int len = 0;
|
||||
char done = 0;
|
||||
int i;
|
||||
/* If they send more than 50 lines, something is wrong */
|
||||
for (i = 0; i < 50; i++) {
|
||||
|
||||
/* Servers may send other lines of data before sending the
|
||||
* version string, client must be able to process such lines.
|
||||
* If they send more than 50 lines, something is wrong */
|
||||
for (i = IS_DROPBEAR_CLIENT ? 50 : 1; i > 0; i--) {
|
||||
len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
|
||||
|
||||
if (len < 0 && errno != EINTR) {
|
||||
|
||||
52
configure.ac
52
configure.ac
@@ -323,17 +323,39 @@ AC_ARG_ENABLE(shadow,
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(plugin,
|
||||
[ --enable-plugin Enable support for External Public Key Authentication plug-in],
|
||||
[
|
||||
AC_DEFINE(DROPBEAR_PLUGIN, 1, External Public Key Authentication)
|
||||
AC_MSG_NOTICE(Enabling support for External Public Key Authentication)
|
||||
DROPBEAR_PLUGIN=1
|
||||
],
|
||||
[
|
||||
AC_DEFINE(DROPBEAR_PLUGIN, 0, External Public Key Authentication)
|
||||
DROPBEAR_PLUGIN=0
|
||||
]
|
||||
|
||||
)
|
||||
AC_SUBST(DROPBEAR_PLUGIN)
|
||||
|
||||
AC_ARG_ENABLE(fuzz,
|
||||
[ --enable-fuzz Build fuzzing. Not recommended for deployment.],
|
||||
[
|
||||
AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing)
|
||||
AC_MSG_NOTICE(Enabling fuzzing)
|
||||
DROPBEAR_FUZZ=1
|
||||
# libfuzzer needs linking with c++ libraries
|
||||
AC_PROG_CXX
|
||||
if test "x$enableval" = "xyes"; then
|
||||
AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing)
|
||||
AC_MSG_NOTICE(Enabling fuzzing)
|
||||
DROPBEAR_FUZZ=1
|
||||
# libfuzzer needs linking with c++ libraries
|
||||
AC_PROG_CXX
|
||||
else
|
||||
AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
|
||||
AC_MSG_NOTICE(Disabling fuzzing)
|
||||
DROPBEAR_FUZZ=0
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
|
||||
AC_MSG_NOTICE(Disabling fuzzing)
|
||||
DROPBEAR_FUZZ=0
|
||||
]
|
||||
|
||||
@@ -348,7 +370,8 @@ AC_CHECK_HEADERS([netinet/in.h netinet/tcp.h \
|
||||
crypt.h \
|
||||
pty.h libutil.h libgen.h inttypes.h stropts.h utmp.h \
|
||||
utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h \
|
||||
pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h])
|
||||
pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h \
|
||||
sys/random.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
@@ -504,27 +527,28 @@ AC_CHECK_FUNCS(clock_gettime)
|
||||
AC_CHECK_HEADERS([mach/mach_time.h])
|
||||
AC_CHECK_FUNCS(mach_absolute_time)
|
||||
|
||||
AC_CHECK_FUNCS(explicit_bzero memset_s)
|
||||
AC_CHECK_FUNCS(explicit_bzero memset_s getrandom)
|
||||
|
||||
AC_ARG_ENABLE(bundled-libtom,
|
||||
[ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists.
|
||||
--disable-bundled-libtom Force using system libtomcrypt/libtommath, fail if it does not exist.
|
||||
Default is to use system if available, otherwise bundled.],
|
||||
Default is to use system if available, otherwise bundled.
|
||||
Dropbear requires system libtommath >= 1.2.0 and libtomcrypt >= 1.18.0],
|
||||
[
|
||||
if test "x$enableval" = "xyes"; then
|
||||
BUNDLED_LIBTOM=1
|
||||
AC_MSG_NOTICE(Forcing bundled libtom*)
|
||||
else
|
||||
BUNDLED_LIBTOM=0
|
||||
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS",
|
||||
[AC_MSG_ERROR([Missing system libtommath and --disable-bundled-libtom was specified])] )
|
||||
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS",
|
||||
[AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] )
|
||||
AC_CHECK_LIB(tommath, mp_to_ubin, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS",
|
||||
[AC_MSG_ERROR([Missing/old system libtommath and --disable-bundled-libtom was specified])] )
|
||||
AC_CHECK_LIB(tomcrypt, poly1305_init, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS",
|
||||
[AC_MSG_ERROR([Missing/old system libtomcrypt and --disable-bundled-libtom was specified])] )
|
||||
fi
|
||||
],
|
||||
[
|
||||
BUNDLED_LIBTOM=0
|
||||
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
|
||||
AC_CHECK_LIB(tommath, mp_to_ubin, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
|
||||
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
|
||||
]
|
||||
)
|
||||
@@ -858,4 +882,4 @@ AC_MSG_NOTICE([crypt() not available, dropbear server will not have password aut
|
||||
fi
|
||||
|
||||
AC_MSG_NOTICE()
|
||||
AC_MSG_NOTICE([Now edit options.h to choose features.])
|
||||
AC_MSG_NOTICE([Now edit localoptions.h to choose features.])
|
||||
|
||||
@@ -1,860 +0,0 @@
|
||||
/* Copyright 2008, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* curve25519-donna: Curve25519 elliptic curve, public key function
|
||||
*
|
||||
* http://code.google.com/p/curve25519-donna/
|
||||
*
|
||||
* Adam Langley <agl@imperialviolet.org>
|
||||
*
|
||||
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
|
||||
*
|
||||
* More information about curve25519 can be found here
|
||||
* http://cr.yp.to/ecdh.html
|
||||
*
|
||||
* djb's sample implementation of curve25519 is written in a special assembly
|
||||
* language called qhasm and uses the floating point registers.
|
||||
*
|
||||
* This is, almost, a clean room reimplementation from the curve25519 paper. It
|
||||
* uses many of the tricks described therein. Only the crecip function is taken
|
||||
* from the sample implementation. */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t limb;
|
||||
|
||||
/* Field element representation:
|
||||
*
|
||||
* Field elements are written as an array of signed, 64-bit limbs, least
|
||||
* significant first. The value of the field element is:
|
||||
* x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ...
|
||||
*
|
||||
* i.e. the limbs are 26, 25, 26, 25, ... bits wide. */
|
||||
|
||||
/* Sum two numbers: output += in */
|
||||
static void fsum(limb *output, const limb *in) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 10; i += 2) {
|
||||
output[0+i] = output[0+i] + in[0+i];
|
||||
output[1+i] = output[1+i] + in[1+i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the difference of two numbers: output = in - output
|
||||
* (note the order of the arguments!). */
|
||||
static void fdifference(limb *output, const limb *in) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 10; ++i) {
|
||||
output[i] = in[i] - output[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Multiply a number by a scalar: output = in * scalar */
|
||||
static void fscalar_product(limb *output, const limb *in, const limb scalar) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 10; ++i) {
|
||||
output[i] = in[i] * scalar;
|
||||
}
|
||||
}
|
||||
|
||||
/* Multiply two numbers: output = in2 * in
|
||||
*
|
||||
* output must be distinct to both inputs. The inputs are reduced coefficient
|
||||
* form, the output is not.
|
||||
*
|
||||
* output[x] <= 14 * the largest product of the input limbs. */
|
||||
static void fproduct(limb *output, const limb *in2, const limb *in) {
|
||||
output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]);
|
||||
output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[0]);
|
||||
output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[0]);
|
||||
output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[0]);
|
||||
output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) +
|
||||
2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[0]);
|
||||
output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[0]);
|
||||
output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[0]);
|
||||
output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[0]);
|
||||
output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) +
|
||||
2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[0]);
|
||||
output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[0]);
|
||||
output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[2]);
|
||||
output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[2]);
|
||||
output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) +
|
||||
2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[3])) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[4]);
|
||||
output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[4]);
|
||||
output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[5])) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[6]);
|
||||
output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[6]);
|
||||
output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[7]));
|
||||
output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[8]);
|
||||
output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]);
|
||||
}
|
||||
|
||||
/* Reduce a long form to a short form by taking the input mod 2^255 - 19.
|
||||
*
|
||||
* On entry: |output[i]| < 14*2^54
|
||||
* On exit: |output[0..8]| < 280*2^54 */
|
||||
static void freduce_degree(limb *output) {
|
||||
/* Each of these shifts and adds ends up multiplying the value by 19.
|
||||
*
|
||||
* For output[0..8], the absolute entry value is < 14*2^54 and we add, at
|
||||
* most, 19*14*2^54 thus, on exit, |output[0..8]| < 280*2^54. */
|
||||
output[8] += output[18] << 4;
|
||||
output[8] += output[18] << 1;
|
||||
output[8] += output[18];
|
||||
output[7] += output[17] << 4;
|
||||
output[7] += output[17] << 1;
|
||||
output[7] += output[17];
|
||||
output[6] += output[16] << 4;
|
||||
output[6] += output[16] << 1;
|
||||
output[6] += output[16];
|
||||
output[5] += output[15] << 4;
|
||||
output[5] += output[15] << 1;
|
||||
output[5] += output[15];
|
||||
output[4] += output[14] << 4;
|
||||
output[4] += output[14] << 1;
|
||||
output[4] += output[14];
|
||||
output[3] += output[13] << 4;
|
||||
output[3] += output[13] << 1;
|
||||
output[3] += output[13];
|
||||
output[2] += output[12] << 4;
|
||||
output[2] += output[12] << 1;
|
||||
output[2] += output[12];
|
||||
output[1] += output[11] << 4;
|
||||
output[1] += output[11] << 1;
|
||||
output[1] += output[11];
|
||||
output[0] += output[10] << 4;
|
||||
output[0] += output[10] << 1;
|
||||
output[0] += output[10];
|
||||
}
|
||||
|
||||
#if (-1 & 3) != 3
|
||||
#error "This code only works on a two's complement system"
|
||||
#endif
|
||||
|
||||
/* return v / 2^26, using only shifts and adds.
|
||||
*
|
||||
* On entry: v can take any value. */
|
||||
static inline limb
|
||||
div_by_2_26(const limb v)
|
||||
{
|
||||
/* High word of v; no shift needed. */
|
||||
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
|
||||
/* Set to all 1s if v was negative; else set to 0s. */
|
||||
const int32_t sign = ((int32_t) highword) >> 31;
|
||||
/* Set to 0x3ffffff if v was negative; else set to 0. */
|
||||
const int32_t roundoff = ((uint32_t) sign) >> 6;
|
||||
/* Should return v / (1<<26) */
|
||||
return (v + roundoff) >> 26;
|
||||
}
|
||||
|
||||
/* return v / (2^25), using only shifts and adds.
|
||||
*
|
||||
* On entry: v can take any value. */
|
||||
static inline limb
|
||||
div_by_2_25(const limb v)
|
||||
{
|
||||
/* High word of v; no shift needed*/
|
||||
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
|
||||
/* Set to all 1s if v was negative; else set to 0s. */
|
||||
const int32_t sign = ((int32_t) highword) >> 31;
|
||||
/* Set to 0x1ffffff if v was negative; else set to 0. */
|
||||
const int32_t roundoff = ((uint32_t) sign) >> 7;
|
||||
/* Should return v / (1<<25) */
|
||||
return (v + roundoff) >> 25;
|
||||
}
|
||||
|
||||
/* Reduce all coefficients of the short form input so that |x| < 2^26.
|
||||
*
|
||||
* On entry: |output[i]| < 280*2^54 */
|
||||
static void freduce_coefficients(limb *output) {
|
||||
unsigned i;
|
||||
|
||||
output[10] = 0;
|
||||
|
||||
for (i = 0; i < 10; i += 2) {
|
||||
limb over = div_by_2_26(output[i]);
|
||||
/* The entry condition (that |output[i]| < 280*2^54) means that over is, at
|
||||
* most, 280*2^28 in the first iteration of this loop. This is added to the
|
||||
* next limb and we can approximate the resulting bound of that limb by
|
||||
* 281*2^54. */
|
||||
output[i] -= over << 26;
|
||||
output[i+1] += over;
|
||||
|
||||
/* For the first iteration, |output[i+1]| < 281*2^54, thus |over| <
|
||||
* 281*2^29. When this is added to the next limb, the resulting bound can
|
||||
* be approximated as 281*2^54.
|
||||
*
|
||||
* For subsequent iterations of the loop, 281*2^54 remains a conservative
|
||||
* bound and no overflow occurs. */
|
||||
over = div_by_2_25(output[i+1]);
|
||||
output[i+1] -= over << 25;
|
||||
output[i+2] += over;
|
||||
}
|
||||
/* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */
|
||||
output[0] += output[10] << 4;
|
||||
output[0] += output[10] << 1;
|
||||
output[0] += output[10];
|
||||
|
||||
output[10] = 0;
|
||||
|
||||
/* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29
|
||||
* So |over| will be no more than 2^16. */
|
||||
{
|
||||
limb over = div_by_2_26(output[0]);
|
||||
output[0] -= over << 26;
|
||||
output[1] += over;
|
||||
}
|
||||
|
||||
/* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The
|
||||
* bound on |output[1]| is sufficient to meet our needs. */
|
||||
}
|
||||
|
||||
/* A helpful wrapper around fproduct: output = in * in2.
|
||||
*
|
||||
* On entry: |in[i]| < 2^27 and |in2[i]| < 2^27.
|
||||
*
|
||||
* output must be distinct to both inputs. The output is reduced degree
|
||||
* (indeed, one need only provide storage for 10 limbs) and |output[i]| < 2^26. */
|
||||
static void
|
||||
fmul(limb *output, const limb *in, const limb *in2) {
|
||||
limb t[19];
|
||||
fproduct(t, in, in2);
|
||||
/* |t[i]| < 14*2^54 */
|
||||
freduce_degree(t);
|
||||
freduce_coefficients(t);
|
||||
/* |t[i]| < 2^26 */
|
||||
memcpy(output, t, sizeof(limb) * 10);
|
||||
}
|
||||
|
||||
/* Square a number: output = in**2
|
||||
*
|
||||
* output must be distinct from the input. The inputs are reduced coefficient
|
||||
* form, the output is not.
|
||||
*
|
||||
* output[x] <= 14 * the largest product of the input limbs. */
|
||||
static void fsquare_inner(limb *output, const limb *in) {
|
||||
output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]);
|
||||
output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]);
|
||||
output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[2]));
|
||||
output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[3]));
|
||||
output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) +
|
||||
4 * ((limb) ((s32) in[1])) * ((s32) in[3]) +
|
||||
2 * ((limb) ((s32) in[0])) * ((s32) in[4]);
|
||||
output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[5]));
|
||||
output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[6]) +
|
||||
2 * ((limb) ((s32) in[1])) * ((s32) in[5]));
|
||||
output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[7]));
|
||||
output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) +
|
||||
2 * (((limb) ((s32) in[2])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in[1])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[5])));
|
||||
output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[9]));
|
||||
output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in[4])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in[3])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[9])));
|
||||
output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[4])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[9]));
|
||||
output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) +
|
||||
2 * (((limb) ((s32) in[4])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in[5])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[9])));
|
||||
output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[5])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[4])) * ((s32) in[9]));
|
||||
output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[6])) * ((s32) in[8]) +
|
||||
2 * ((limb) ((s32) in[5])) * ((s32) in[9]));
|
||||
output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[6])) * ((s32) in[9]));
|
||||
output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) +
|
||||
4 * ((limb) ((s32) in[7])) * ((s32) in[9]);
|
||||
output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]);
|
||||
output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]);
|
||||
}
|
||||
|
||||
/* fsquare sets output = in^2.
|
||||
*
|
||||
* On entry: The |in| argument is in reduced coefficients form and |in[i]| <
|
||||
* 2^27.
|
||||
*
|
||||
* On exit: The |output| argument is in reduced coefficients form (indeed, one
|
||||
* need only provide storage for 10 limbs) and |out[i]| < 2^26. */
|
||||
static void
|
||||
fsquare(limb *output, const limb *in) {
|
||||
limb t[19];
|
||||
fsquare_inner(t, in);
|
||||
/* |t[i]| < 14*2^54 because the largest product of two limbs will be <
|
||||
* 2^(27+27) and fsquare_inner adds together, at most, 14 of those
|
||||
* products. */
|
||||
freduce_degree(t);
|
||||
freduce_coefficients(t);
|
||||
/* |t[i]| < 2^26 */
|
||||
memcpy(output, t, sizeof(limb) * 10);
|
||||
}
|
||||
|
||||
/* Take a little-endian, 32-byte number and expand it into polynomial form */
|
||||
static void
|
||||
fexpand(limb *output, const u8 *input) {
|
||||
#define F(n,start,shift,mask) \
|
||||
output[n] = ((((limb) input[start + 0]) | \
|
||||
((limb) input[start + 1]) << 8 | \
|
||||
((limb) input[start + 2]) << 16 | \
|
||||
((limb) input[start + 3]) << 24) >> shift) & mask;
|
||||
F(0, 0, 0, 0x3ffffff);
|
||||
F(1, 3, 2, 0x1ffffff);
|
||||
F(2, 6, 3, 0x3ffffff);
|
||||
F(3, 9, 5, 0x1ffffff);
|
||||
F(4, 12, 6, 0x3ffffff);
|
||||
F(5, 16, 0, 0x1ffffff);
|
||||
F(6, 19, 1, 0x3ffffff);
|
||||
F(7, 22, 3, 0x1ffffff);
|
||||
F(8, 25, 4, 0x3ffffff);
|
||||
F(9, 28, 6, 0x1ffffff);
|
||||
#undef F
|
||||
}
|
||||
|
||||
#if (-32 >> 1) != -16
|
||||
#error "This code only works when >> does sign-extension on negative numbers"
|
||||
#endif
|
||||
|
||||
/* s32_eq returns 0xffffffff iff a == b and zero otherwise. */
|
||||
static s32 s32_eq(s32 a, s32 b) {
|
||||
a = ~(a ^ b);
|
||||
a &= a << 16;
|
||||
a &= a << 8;
|
||||
a &= a << 4;
|
||||
a &= a << 2;
|
||||
a &= a << 1;
|
||||
return a >> 31;
|
||||
}
|
||||
|
||||
/* s32_gte returns 0xffffffff if a >= b and zero otherwise, where a and b are
|
||||
* both non-negative. */
|
||||
static s32 s32_gte(s32 a, s32 b) {
|
||||
a -= b;
|
||||
/* a >= 0 iff a >= b. */
|
||||
return ~(a >> 31);
|
||||
}
|
||||
|
||||
/* Take a fully reduced polynomial form number and contract it into a
|
||||
* little-endian, 32-byte array.
|
||||
*
|
||||
* On entry: |input_limbs[i]| < 2^26 */
|
||||
static void
|
||||
fcontract(u8 *output, limb *input_limbs) {
|
||||
int i;
|
||||
int j;
|
||||
s32 input[10];
|
||||
s32 mask;
|
||||
|
||||
/* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */
|
||||
for (i = 0; i < 10; i++) {
|
||||
input[i] = input_limbs[i];
|
||||
}
|
||||
|
||||
for (j = 0; j < 2; ++j) {
|
||||
for (i = 0; i < 9; ++i) {
|
||||
if ((i & 1) == 1) {
|
||||
/* This calculation is a time-invariant way to make input[i]
|
||||
* non-negative by borrowing from the next-larger limb. */
|
||||
const s32 mask = input[i] >> 31;
|
||||
const s32 carry = -((input[i] & mask) >> 25);
|
||||
input[i] = input[i] + (carry << 25);
|
||||
input[i+1] = input[i+1] - carry;
|
||||
} else {
|
||||
const s32 mask = input[i] >> 31;
|
||||
const s32 carry = -((input[i] & mask) >> 26);
|
||||
input[i] = input[i] + (carry << 26);
|
||||
input[i+1] = input[i+1] - carry;
|
||||
}
|
||||
}
|
||||
|
||||
/* There's no greater limb for input[9] to borrow from, but we can multiply
|
||||
* by 19 and borrow from input[0], which is valid mod 2^255-19. */
|
||||
{
|
||||
const s32 mask = input[9] >> 31;
|
||||
const s32 carry = -((input[9] & mask) >> 25);
|
||||
input[9] = input[9] + (carry << 25);
|
||||
input[0] = input[0] - (carry * 19);
|
||||
}
|
||||
|
||||
/* After the first iteration, input[1..9] are non-negative and fit within
|
||||
* 25 or 26 bits, depending on position. However, input[0] may be
|
||||
* negative. */
|
||||
}
|
||||
|
||||
/* The first borrow-propagation pass above ended with every limb
|
||||
except (possibly) input[0] non-negative.
|
||||
|
||||
If input[0] was negative after the first pass, then it was because of a
|
||||
carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most,
|
||||
one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19.
|
||||
|
||||
In the second pass, each limb is decreased by at most one. Thus the second
|
||||
borrow-propagation pass could only have wrapped around to decrease
|
||||
input[0] again if the first pass left input[0] negative *and* input[1]
|
||||
through input[9] were all zero. In that case, input[1] is now 2^25 - 1,
|
||||
and this last borrow-propagation step will leave input[1] non-negative. */
|
||||
{
|
||||
const s32 mask = input[0] >> 31;
|
||||
const s32 carry = -((input[0] & mask) >> 26);
|
||||
input[0] = input[0] + (carry << 26);
|
||||
input[1] = input[1] - carry;
|
||||
}
|
||||
|
||||
/* All input[i] are now non-negative. However, there might be values between
|
||||
* 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */
|
||||
for (j = 0; j < 2; j++) {
|
||||
for (i = 0; i < 9; i++) {
|
||||
if ((i & 1) == 1) {
|
||||
const s32 carry = input[i] >> 25;
|
||||
input[i] &= 0x1ffffff;
|
||||
input[i+1] += carry;
|
||||
} else {
|
||||
const s32 carry = input[i] >> 26;
|
||||
input[i] &= 0x3ffffff;
|
||||
input[i+1] += carry;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const s32 carry = input[9] >> 25;
|
||||
input[9] &= 0x1ffffff;
|
||||
input[0] += 19*carry;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the first carry-chain pass, just above, ended up with a carry from
|
||||
* input[9], and that caused input[0] to be out-of-bounds, then input[0] was
|
||||
* < 2^26 + 2*19, because the carry was, at most, two.
|
||||
*
|
||||
* If the second pass carried from input[9] again then input[0] is < 2*19 and
|
||||
* the input[9] -> input[0] carry didn't push input[0] out of bounds. */
|
||||
|
||||
/* It still remains the case that input might be between 2^255-19 and 2^255.
|
||||
* In this case, input[1..9] must take their maximum value and input[0] must
|
||||
* be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */
|
||||
mask = s32_gte(input[0], 0x3ffffed);
|
||||
for (i = 1; i < 10; i++) {
|
||||
if ((i & 1) == 1) {
|
||||
mask &= s32_eq(input[i], 0x1ffffff);
|
||||
} else {
|
||||
mask &= s32_eq(input[i], 0x3ffffff);
|
||||
}
|
||||
}
|
||||
|
||||
/* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus
|
||||
* this conditionally subtracts 2^255-19. */
|
||||
input[0] -= mask & 0x3ffffed;
|
||||
|
||||
for (i = 1; i < 10; i++) {
|
||||
if ((i & 1) == 1) {
|
||||
input[i] -= mask & 0x1ffffff;
|
||||
} else {
|
||||
input[i] -= mask & 0x3ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
input[1] <<= 2;
|
||||
input[2] <<= 3;
|
||||
input[3] <<= 5;
|
||||
input[4] <<= 6;
|
||||
input[6] <<= 1;
|
||||
input[7] <<= 3;
|
||||
input[8] <<= 4;
|
||||
input[9] <<= 6;
|
||||
#define F(i, s) \
|
||||
output[s+0] |= input[i] & 0xff; \
|
||||
output[s+1] = (input[i] >> 8) & 0xff; \
|
||||
output[s+2] = (input[i] >> 16) & 0xff; \
|
||||
output[s+3] = (input[i] >> 24) & 0xff;
|
||||
output[0] = 0;
|
||||
output[16] = 0;
|
||||
F(0,0);
|
||||
F(1,3);
|
||||
F(2,6);
|
||||
F(3,9);
|
||||
F(4,12);
|
||||
F(5,16);
|
||||
F(6,19);
|
||||
F(7,22);
|
||||
F(8,25);
|
||||
F(9,28);
|
||||
#undef F
|
||||
}
|
||||
|
||||
/* Input: Q, Q', Q-Q'
|
||||
* Output: 2Q, Q+Q'
|
||||
*
|
||||
* x2 z3: long form
|
||||
* x3 z3: long form
|
||||
* x z: short form, destroyed
|
||||
* xprime zprime: short form, destroyed
|
||||
* qmqp: short form, preserved
|
||||
*
|
||||
* On entry and exit, the absolute value of the limbs of all inputs and outputs
|
||||
* are < 2^26. */
|
||||
static void fmonty(limb *x2, limb *z2, /* output 2Q */
|
||||
limb *x3, limb *z3, /* output Q + Q' */
|
||||
limb *x, limb *z, /* input Q */
|
||||
limb *xprime, limb *zprime, /* input Q' */
|
||||
const limb *qmqp /* input Q - Q' */) {
|
||||
limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19],
|
||||
zzprime[19], zzzprime[19], xxxprime[19];
|
||||
|
||||
memcpy(origx, x, 10 * sizeof(limb));
|
||||
fsum(x, z);
|
||||
/* |x[i]| < 2^27 */
|
||||
fdifference(z, origx); /* does x - z */
|
||||
/* |z[i]| < 2^27 */
|
||||
|
||||
memcpy(origxprime, xprime, sizeof(limb) * 10);
|
||||
fsum(xprime, zprime);
|
||||
/* |xprime[i]| < 2^27 */
|
||||
fdifference(zprime, origxprime);
|
||||
/* |zprime[i]| < 2^27 */
|
||||
fproduct(xxprime, xprime, z);
|
||||
/* |xxprime[i]| < 14*2^54: the largest product of two limbs will be <
|
||||
* 2^(27+27) and fproduct adds together, at most, 14 of those products.
|
||||
* (Approximating that to 2^58 doesn't work out.) */
|
||||
fproduct(zzprime, x, zprime);
|
||||
/* |zzprime[i]| < 14*2^54 */
|
||||
freduce_degree(xxprime);
|
||||
freduce_coefficients(xxprime);
|
||||
/* |xxprime[i]| < 2^26 */
|
||||
freduce_degree(zzprime);
|
||||
freduce_coefficients(zzprime);
|
||||
/* |zzprime[i]| < 2^26 */
|
||||
memcpy(origxprime, xxprime, sizeof(limb) * 10);
|
||||
fsum(xxprime, zzprime);
|
||||
/* |xxprime[i]| < 2^27 */
|
||||
fdifference(zzprime, origxprime);
|
||||
/* |zzprime[i]| < 2^27 */
|
||||
fsquare(xxxprime, xxprime);
|
||||
/* |xxxprime[i]| < 2^26 */
|
||||
fsquare(zzzprime, zzprime);
|
||||
/* |zzzprime[i]| < 2^26 */
|
||||
fproduct(zzprime, zzzprime, qmqp);
|
||||
/* |zzprime[i]| < 14*2^52 */
|
||||
freduce_degree(zzprime);
|
||||
freduce_coefficients(zzprime);
|
||||
/* |zzprime[i]| < 2^26 */
|
||||
memcpy(x3, xxxprime, sizeof(limb) * 10);
|
||||
memcpy(z3, zzprime, sizeof(limb) * 10);
|
||||
|
||||
fsquare(xx, x);
|
||||
/* |xx[i]| < 2^26 */
|
||||
fsquare(zz, z);
|
||||
/* |zz[i]| < 2^26 */
|
||||
fproduct(x2, xx, zz);
|
||||
/* |x2[i]| < 14*2^52 */
|
||||
freduce_degree(x2);
|
||||
freduce_coefficients(x2);
|
||||
/* |x2[i]| < 2^26 */
|
||||
fdifference(zz, xx); /* does zz = xx - zz */
|
||||
/* |zz[i]| < 2^27 */
|
||||
memset(zzz + 10, 0, sizeof(limb) * 9);
|
||||
fscalar_product(zzz, zz, 121665);
|
||||
/* |zzz[i]| < 2^(27+17) */
|
||||
/* No need to call freduce_degree here:
|
||||
fscalar_product doesn't increase the degree of its input. */
|
||||
freduce_coefficients(zzz);
|
||||
/* |zzz[i]| < 2^26 */
|
||||
fsum(zzz, xx);
|
||||
/* |zzz[i]| < 2^27 */
|
||||
fproduct(z2, zz, zzz);
|
||||
/* |z2[i]| < 14*2^(26+27) */
|
||||
freduce_degree(z2);
|
||||
freduce_coefficients(z2);
|
||||
/* |z2|i| < 2^26 */
|
||||
}
|
||||
|
||||
/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave
|
||||
* them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid
|
||||
* side-channel attacks.
|
||||
*
|
||||
* NOTE that this function requires that 'iswap' be 1 or 0; other values give
|
||||
* wrong results. Also, the two limb arrays must be in reduced-coefficient,
|
||||
* reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped,
|
||||
* and all all values in a[0..9],b[0..9] must have magnitude less than
|
||||
* INT32_MAX. */
|
||||
static void
|
||||
swap_conditional(limb a[19], limb b[19], limb iswap) {
|
||||
unsigned i;
|
||||
const s32 swap = (s32) -iswap;
|
||||
|
||||
for (i = 0; i < 10; ++i) {
|
||||
const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) );
|
||||
a[i] = ((s32)a[i]) ^ x;
|
||||
b[i] = ((s32)b[i]) ^ x;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculates nQ where Q is the x-coordinate of a point on the curve
|
||||
*
|
||||
* resultx/resultz: the x coordinate of the resulting curve point (short form)
|
||||
* n: a little endian, 32-byte number
|
||||
* q: a point of the curve (short form) */
|
||||
static void
|
||||
cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
|
||||
limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0};
|
||||
limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
|
||||
limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1};
|
||||
limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
|
||||
|
||||
unsigned i, j;
|
||||
|
||||
memcpy(nqpqx, q, sizeof(limb) * 10);
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
u8 byte = n[31 - i];
|
||||
for (j = 0; j < 8; ++j) {
|
||||
const limb bit = byte >> 7;
|
||||
|
||||
swap_conditional(nqx, nqpqx, bit);
|
||||
swap_conditional(nqz, nqpqz, bit);
|
||||
fmonty(nqx2, nqz2,
|
||||
nqpqx2, nqpqz2,
|
||||
nqx, nqz,
|
||||
nqpqx, nqpqz,
|
||||
q);
|
||||
swap_conditional(nqx2, nqpqx2, bit);
|
||||
swap_conditional(nqz2, nqpqz2, bit);
|
||||
|
||||
t = nqx;
|
||||
nqx = nqx2;
|
||||
nqx2 = t;
|
||||
t = nqz;
|
||||
nqz = nqz2;
|
||||
nqz2 = t;
|
||||
t = nqpqx;
|
||||
nqpqx = nqpqx2;
|
||||
nqpqx2 = t;
|
||||
t = nqpqz;
|
||||
nqpqz = nqpqz2;
|
||||
nqpqz2 = t;
|
||||
|
||||
byte <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(resultx, nqx, sizeof(limb) * 10);
|
||||
memcpy(resultz, nqz, sizeof(limb) * 10);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Shamelessly copied from djb's code
|
||||
* ----------------------------------------------------------------------------- */
|
||||
static void
|
||||
crecip(limb *out, const limb *z) {
|
||||
limb z2[10];
|
||||
limb z9[10];
|
||||
limb z11[10];
|
||||
limb z2_5_0[10];
|
||||
limb z2_10_0[10];
|
||||
limb z2_20_0[10];
|
||||
limb z2_50_0[10];
|
||||
limb z2_100_0[10];
|
||||
limb t0[10];
|
||||
limb t1[10];
|
||||
int i;
|
||||
|
||||
/* 2 */ fsquare(z2,z);
|
||||
/* 4 */ fsquare(t1,z2);
|
||||
/* 8 */ fsquare(t0,t1);
|
||||
/* 9 */ fmul(z9,t0,z);
|
||||
/* 11 */ fmul(z11,z9,z2);
|
||||
/* 22 */ fsquare(t0,z11);
|
||||
/* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9);
|
||||
|
||||
/* 2^6 - 2^1 */ fsquare(t0,z2_5_0);
|
||||
/* 2^7 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^8 - 2^3 */ fsquare(t0,t1);
|
||||
/* 2^9 - 2^4 */ fsquare(t1,t0);
|
||||
/* 2^10 - 2^5 */ fsquare(t0,t1);
|
||||
/* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0);
|
||||
|
||||
/* 2^11 - 2^1 */ fsquare(t0,z2_10_0);
|
||||
/* 2^12 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0);
|
||||
|
||||
/* 2^21 - 2^1 */ fsquare(t0,z2_20_0);
|
||||
/* 2^22 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0);
|
||||
|
||||
/* 2^41 - 2^1 */ fsquare(t1,t0);
|
||||
/* 2^42 - 2^2 */ fsquare(t0,t1);
|
||||
/* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
|
||||
/* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0);
|
||||
|
||||
/* 2^51 - 2^1 */ fsquare(t0,z2_50_0);
|
||||
/* 2^52 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0);
|
||||
|
||||
/* 2^101 - 2^1 */ fsquare(t1,z2_100_0);
|
||||
/* 2^102 - 2^2 */ fsquare(t0,t1);
|
||||
/* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
|
||||
/* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0);
|
||||
|
||||
/* 2^201 - 2^1 */ fsquare(t0,t1);
|
||||
/* 2^202 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0);
|
||||
|
||||
/* 2^251 - 2^1 */ fsquare(t1,t0);
|
||||
/* 2^252 - 2^2 */ fsquare(t0,t1);
|
||||
/* 2^253 - 2^3 */ fsquare(t1,t0);
|
||||
/* 2^254 - 2^4 */ fsquare(t0,t1);
|
||||
/* 2^255 - 2^5 */ fsquare(t1,t0);
|
||||
/* 2^255 - 21 */ fmul(out,t1,z11);
|
||||
}
|
||||
|
||||
int
|
||||
curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
|
||||
limb bp[10], x[10], z[11], zmone[10];
|
||||
uint8_t e[32];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; ++i) e[i] = secret[i];
|
||||
e[0] &= 248;
|
||||
e[31] &= 127;
|
||||
e[31] |= 64;
|
||||
|
||||
fexpand(bp, basepoint);
|
||||
cmult(x, z, e, bp);
|
||||
crecip(zmone, z);
|
||||
fmul(z, x, zmone);
|
||||
fcontract(mypublic, z);
|
||||
return 0;
|
||||
}
|
||||
497
curve25519.c
Normal file
497
curve25519.c
Normal file
@@ -0,0 +1,497 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbrandom.h"
|
||||
#include "curve25519.h"
|
||||
|
||||
#if DROPBEAR_CURVE25519 || DROPBEAR_ED25519
|
||||
|
||||
/* Modified TweetNaCl version 20140427, a self-contained public-domain C library.
|
||||
* https://tweetnacl.cr.yp.to/ */
|
||||
|
||||
#define FOR(i,n) for (i = 0;i < n;++i)
|
||||
#define sv static void
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned long u32;
|
||||
typedef unsigned long long u64;
|
||||
typedef long long i64;
|
||||
typedef i64 gf[16];
|
||||
|
||||
#if DROPBEAR_CURVE25519
|
||||
static const gf
|
||||
_121665 = {0xDB41,1};
|
||||
#endif /* DROPBEAR_CURVE25519 */
|
||||
#if DROPBEAR_ED25519
|
||||
static const gf
|
||||
gf0,
|
||||
gf1 = {1},
|
||||
D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406},
|
||||
X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169},
|
||||
Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666};
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static const gf
|
||||
D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203},
|
||||
I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83};
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static int vn(const u8 *x,const u8 *y,u32 n)
|
||||
{
|
||||
u32 i,d = 0;
|
||||
FOR(i,n) d |= x[i]^y[i];
|
||||
return (1 & ((d - 1) >> 8)) - 1;
|
||||
}
|
||||
|
||||
static int crypto_verify_32(const u8 *x,const u8 *y)
|
||||
{
|
||||
return vn(x,y,32);
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
sv set25519(gf r, const gf a)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) r[i]=a[i];
|
||||
}
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
sv car25519(gf o)
|
||||
{
|
||||
int i;
|
||||
i64 c;
|
||||
FOR(i,16) {
|
||||
o[i]+=(1LL<<16);
|
||||
c=o[i]>>16;
|
||||
o[(i+1)*(i<15)]+=c-1+37*(c-1)*(i==15);
|
||||
o[i]-=c<<16;
|
||||
}
|
||||
}
|
||||
|
||||
sv sel25519(gf p,gf q,int b)
|
||||
{
|
||||
i64 t,i,c=~(b-1);
|
||||
FOR(i,16) {
|
||||
t= c&(p[i]^q[i]);
|
||||
p[i]^=t;
|
||||
q[i]^=t;
|
||||
}
|
||||
}
|
||||
|
||||
sv pack25519(u8 *o,const gf n)
|
||||
{
|
||||
int i,j,b;
|
||||
gf m,t;
|
||||
FOR(i,16) t[i]=n[i];
|
||||
car25519(t);
|
||||
car25519(t);
|
||||
car25519(t);
|
||||
FOR(j,2) {
|
||||
m[0]=t[0]-0xffed;
|
||||
for(i=1;i<15;i++) {
|
||||
m[i]=t[i]-0xffff-((m[i-1]>>16)&1);
|
||||
m[i-1]&=0xffff;
|
||||
}
|
||||
m[15]=t[15]-0x7fff-((m[14]>>16)&1);
|
||||
b=(m[15]>>16)&1;
|
||||
m[14]&=0xffff;
|
||||
sel25519(t,m,1-b);
|
||||
}
|
||||
FOR(i,16) {
|
||||
o[2*i]=t[i]&0xff;
|
||||
o[2*i+1]=t[i]>>8;
|
||||
}
|
||||
}
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static int neq25519(const gf a, const gf b)
|
||||
{
|
||||
u8 c[32],d[32];
|
||||
pack25519(c,a);
|
||||
pack25519(d,b);
|
||||
return crypto_verify_32(c,d);
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
static u8 par25519(const gf a)
|
||||
{
|
||||
u8 d[32];
|
||||
pack25519(d,a);
|
||||
return d[0]&1;
|
||||
}
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
sv unpack25519(gf o, const u8 *n)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) o[i]=n[2*i]+((i64)n[2*i+1]<<8);
|
||||
o[15]&=0x7fff;
|
||||
}
|
||||
|
||||
sv A(gf o,const gf a,const gf b)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) o[i]=a[i]+b[i];
|
||||
}
|
||||
|
||||
sv Z(gf o,const gf a,const gf b)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) o[i]=a[i]-b[i];
|
||||
}
|
||||
|
||||
sv M(gf o,const gf a,const gf b)
|
||||
{
|
||||
i64 i,j,t[31];
|
||||
FOR(i,31) t[i]=0;
|
||||
FOR(i,16) FOR(j,16) t[i+j]+=a[i]*b[j];
|
||||
FOR(i,15) t[i]+=38*t[i+16];
|
||||
FOR(i,16) o[i]=t[i];
|
||||
car25519(o);
|
||||
car25519(o);
|
||||
}
|
||||
|
||||
sv S(gf o,const gf a)
|
||||
{
|
||||
M(o,a,a);
|
||||
}
|
||||
|
||||
sv inv25519(gf o,const gf i)
|
||||
{
|
||||
gf c;
|
||||
int a;
|
||||
FOR(a,16) c[a]=i[a];
|
||||
for(a=253;a>=0;a--) {
|
||||
S(c,c);
|
||||
if(a!=2&&a!=4) M(c,c,i);
|
||||
}
|
||||
FOR(a,16) o[a]=c[a];
|
||||
}
|
||||
|
||||
#if DROPBEAR_ED25519 && DROPBEAR_SIGNKEY_VERIFY
|
||||
sv pow2523(gf o,const gf i)
|
||||
{
|
||||
gf c;
|
||||
int a;
|
||||
FOR(a,16) c[a]=i[a];
|
||||
for(a=250;a>=0;a--) {
|
||||
S(c,c);
|
||||
if(a!=1) M(c,c,i);
|
||||
}
|
||||
FOR(a,16) o[a]=c[a];
|
||||
}
|
||||
#endif /* DROPBEAR_ED25519 && DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
#if DROPBEAR_CURVE25519
|
||||
void dropbear_curve25519_scalarmult(u8 *q,const u8 *n,const u8 *p)
|
||||
{
|
||||
u8 z[32];
|
||||
i64 x[80],r,i;
|
||||
gf a,b,c,d,e,f;
|
||||
FOR(i,31) z[i]=n[i];
|
||||
z[31]=(n[31]&127)|64;
|
||||
z[0]&=248;
|
||||
unpack25519(x,p);
|
||||
FOR(i,16) {
|
||||
b[i]=x[i];
|
||||
d[i]=a[i]=c[i]=0;
|
||||
}
|
||||
a[0]=d[0]=1;
|
||||
for(i=254;i>=0;--i) {
|
||||
r=(z[i>>3]>>(i&7))&1;
|
||||
sel25519(a,b,r);
|
||||
sel25519(c,d,r);
|
||||
A(e,a,c);
|
||||
Z(a,a,c);
|
||||
A(c,b,d);
|
||||
Z(b,b,d);
|
||||
S(d,e);
|
||||
S(f,a);
|
||||
M(a,c,a);
|
||||
M(c,b,e);
|
||||
A(e,a,c);
|
||||
Z(a,a,c);
|
||||
S(b,a);
|
||||
Z(c,d,f);
|
||||
M(a,c,_121665);
|
||||
A(a,a,d);
|
||||
M(c,c,a);
|
||||
M(a,d,f);
|
||||
M(d,b,x);
|
||||
S(b,e);
|
||||
sel25519(a,b,r);
|
||||
sel25519(c,d,r);
|
||||
}
|
||||
FOR(i,16) {
|
||||
x[i+16]=a[i];
|
||||
x[i+32]=c[i];
|
||||
x[i+48]=b[i];
|
||||
x[i+64]=d[i];
|
||||
}
|
||||
inv25519(x+32,x+32);
|
||||
M(x+16,x+16,x+32);
|
||||
pack25519(q,x+16);
|
||||
}
|
||||
#endif /* DROPBEAR_CURVE25519 */
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
static int crypto_hash(u8 *out,const u8 *m,u64 n)
|
||||
{
|
||||
hash_state hs;
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs, m, n);
|
||||
return sha512_done(&hs, out);
|
||||
}
|
||||
|
||||
sv add(gf p[4],gf q[4])
|
||||
{
|
||||
gf a,b,c,d,t,e,f,g,h;
|
||||
|
||||
Z(a, p[1], p[0]);
|
||||
Z(t, q[1], q[0]);
|
||||
M(a, a, t);
|
||||
A(b, p[0], p[1]);
|
||||
A(t, q[0], q[1]);
|
||||
M(b, b, t);
|
||||
M(c, p[3], q[3]);
|
||||
M(c, c, D2);
|
||||
M(d, p[2], q[2]);
|
||||
A(d, d, d);
|
||||
Z(e, b, a);
|
||||
Z(f, d, c);
|
||||
A(g, d, c);
|
||||
A(h, b, a);
|
||||
|
||||
M(p[0], e, f);
|
||||
M(p[1], h, g);
|
||||
M(p[2], g, f);
|
||||
M(p[3], e, h);
|
||||
}
|
||||
|
||||
sv cswap(gf p[4],gf q[4],u8 b)
|
||||
{
|
||||
int i;
|
||||
FOR(i,4)
|
||||
sel25519(p[i],q[i],b);
|
||||
}
|
||||
|
||||
sv pack(u8 *r,gf p[4])
|
||||
{
|
||||
gf tx, ty, zi;
|
||||
inv25519(zi, p[2]);
|
||||
M(tx, p[0], zi);
|
||||
M(ty, p[1], zi);
|
||||
pack25519(r, ty);
|
||||
r[31] ^= par25519(tx) << 7;
|
||||
}
|
||||
|
||||
sv scalarmult(gf p[4],gf q[4],const u8 *s)
|
||||
{
|
||||
int i;
|
||||
set25519(p[0],gf0);
|
||||
set25519(p[1],gf1);
|
||||
set25519(p[2],gf1);
|
||||
set25519(p[3],gf0);
|
||||
for (i = 255;i >= 0;--i) {
|
||||
u8 b = (s[i/8]>>(i&7))&1;
|
||||
cswap(p,q,b);
|
||||
add(q,p);
|
||||
add(p,p);
|
||||
cswap(p,q,b);
|
||||
}
|
||||
}
|
||||
|
||||
sv scalarbase(gf p[4],const u8 *s)
|
||||
{
|
||||
gf q[4];
|
||||
set25519(q[0],X);
|
||||
set25519(q[1],Y);
|
||||
set25519(q[2],gf1);
|
||||
M(q[3],X,Y);
|
||||
scalarmult(p,q,s);
|
||||
}
|
||||
|
||||
void dropbear_ed25519_make_key(u8 *pk,u8 *sk)
|
||||
{
|
||||
u8 d[64];
|
||||
gf p[4];
|
||||
|
||||
genrandom(sk, 32);
|
||||
|
||||
crypto_hash(d, sk, 32);
|
||||
d[0] &= 248;
|
||||
d[31] &= 127;
|
||||
d[31] |= 64;
|
||||
|
||||
scalarbase(p,d);
|
||||
pack(pk,p);
|
||||
}
|
||||
|
||||
static const u64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10};
|
||||
|
||||
sv modL(u8 *r,i64 x[64])
|
||||
{
|
||||
i64 carry,i,j;
|
||||
for (i = 63;i >= 32;--i) {
|
||||
carry = 0;
|
||||
for (j = i - 32;j < i - 12;++j) {
|
||||
x[j] += carry - 16 * x[i] * L[j - (i - 32)];
|
||||
carry = (x[j] + 128) >> 8;
|
||||
x[j] -= carry << 8;
|
||||
}
|
||||
x[j] += carry;
|
||||
x[i] = 0;
|
||||
}
|
||||
carry = 0;
|
||||
FOR(j,32) {
|
||||
x[j] += carry - (x[31] >> 4) * L[j];
|
||||
carry = x[j] >> 8;
|
||||
x[j] &= 255;
|
||||
}
|
||||
FOR(j,32) x[j] -= carry * L[j];
|
||||
FOR(i,32) {
|
||||
x[i+1] += x[i] >> 8;
|
||||
r[i] = x[i] & 255;
|
||||
}
|
||||
}
|
||||
|
||||
sv reduce(u8 *r)
|
||||
{
|
||||
i64 x[64],i;
|
||||
FOR(i,64) x[i] = (u64) r[i];
|
||||
FOR(i,64) r[i] = 0;
|
||||
modL(r,x);
|
||||
}
|
||||
|
||||
void dropbear_ed25519_sign(const u8 *m,u32 mlen,u8 *s,u32 *slen,const u8 *sk, const u8 *pk)
|
||||
{
|
||||
hash_state hs;
|
||||
u8 d[64],h[64],r[64];
|
||||
i64 x[64];
|
||||
gf p[4];
|
||||
u32 i,j;
|
||||
|
||||
crypto_hash(d, sk, 32);
|
||||
d[0] &= 248;
|
||||
d[31] &= 127;
|
||||
d[31] |= 64;
|
||||
|
||||
*slen = 64;
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs,d + 32,32);
|
||||
sha512_process(&hs,m,mlen);
|
||||
sha512_done(&hs,r);
|
||||
reduce(r);
|
||||
scalarbase(p,r);
|
||||
pack(s,p);
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs,s,32);
|
||||
sha512_process(&hs,pk,32);
|
||||
sha512_process(&hs,m,mlen);
|
||||
sha512_done(&hs,h);
|
||||
reduce(h);
|
||||
|
||||
FOR(i,64) x[i] = 0;
|
||||
FOR(i,32) x[i] = (u64) r[i];
|
||||
FOR(i,32) FOR(j,32) x[i+j] += h[i] * (u64) d[j];
|
||||
modL(s + 32,x);
|
||||
}
|
||||
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static int unpackneg(gf r[4],const u8 p[32])
|
||||
{
|
||||
gf t, chk, num, den, den2, den4, den6;
|
||||
set25519(r[2],gf1);
|
||||
unpack25519(r[1],p);
|
||||
S(num,r[1]);
|
||||
M(den,num,D);
|
||||
Z(num,num,r[2]);
|
||||
A(den,r[2],den);
|
||||
|
||||
S(den2,den);
|
||||
S(den4,den2);
|
||||
M(den6,den4,den2);
|
||||
M(t,den6,num);
|
||||
M(t,t,den);
|
||||
|
||||
pow2523(t,t);
|
||||
M(t,t,num);
|
||||
M(t,t,den);
|
||||
M(t,t,den);
|
||||
M(r[0],t,den);
|
||||
|
||||
S(chk,r[0]);
|
||||
M(chk,chk,den);
|
||||
if (neq25519(chk, num)) M(r[0],r[0],I);
|
||||
|
||||
S(chk,r[0]);
|
||||
M(chk,chk,den);
|
||||
if (neq25519(chk, num)) return -1;
|
||||
|
||||
if (par25519(r[0]) == (p[31]>>7)) Z(r[0],gf0,r[0]);
|
||||
|
||||
M(r[3],r[0],r[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dropbear_ed25519_verify(const u8 *m,u32 mlen,const u8 *s,u32 slen,const u8 *pk)
|
||||
{
|
||||
hash_state hs;
|
||||
u8 t[32],h[64];
|
||||
gf p[4],q[4];
|
||||
|
||||
if (slen < 64) return -1;
|
||||
|
||||
if (unpackneg(q,pk)) return -1;
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs,s,32);
|
||||
sha512_process(&hs,pk,32);
|
||||
sha512_process(&hs,m,mlen);
|
||||
sha512_done(&hs,h);
|
||||
|
||||
reduce(h);
|
||||
scalarmult(p,q,h);
|
||||
|
||||
scalarbase(q,s + 32);
|
||||
add(p,q);
|
||||
pack(t,p);
|
||||
|
||||
if (crypto_verify_32(s, t))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
#endif /* DROPBEAR_CURVE25519 || DROPBEAR_ED25519 */
|
||||
37
curve25519.h
Normal file
37
curve25519.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef DROPBEAR_CURVE25519_H
|
||||
#define DROPBEAR_CURVE25519_H
|
||||
|
||||
void dropbear_curve25519_scalarmult(unsigned char *q, const unsigned char *n, const unsigned char *p);
|
||||
void dropbear_ed25519_make_key(unsigned char *pk, unsigned char *sk);
|
||||
void dropbear_ed25519_sign(const unsigned char *m, unsigned long mlen,
|
||||
unsigned char *s, unsigned long *slen,
|
||||
const unsigned char *sk, const unsigned char *pk);
|
||||
int dropbear_ed25519_verify(const unsigned char *m, unsigned long mlen,
|
||||
const unsigned char *s, unsigned long slen,
|
||||
const unsigned char *pk);
|
||||
|
||||
#endif /* DROPBEAR_CURVE25519_H */
|
||||
10
dbmalloc.c
10
dbmalloc.c
@@ -180,3 +180,13 @@ void m_free_direct(void* ptr) {
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_TRACKING_MALLOC */
|
||||
|
||||
void * m_realloc_ltm(void* ptr, size_t oldsize, size_t newsize) {
|
||||
(void)oldsize;
|
||||
return m_realloc(ptr, newsize);
|
||||
}
|
||||
|
||||
void m_free_ltm(void *mem, size_t size) {
|
||||
(void)size;
|
||||
m_free_direct(mem);
|
||||
}
|
||||
|
||||
148
dbrandom.c
148
dbrandom.c
@@ -49,24 +49,19 @@ static int donerandinit = 0;
|
||||
*
|
||||
*/
|
||||
|
||||
/* Pass len=0 to hash an entire file */
|
||||
/* Pass wantlen=0 to hash an entire file */
|
||||
static int
|
||||
process_file(hash_state *hs, const char *filename,
|
||||
unsigned int len, int prngd)
|
||||
{
|
||||
static int already_blocked = 0;
|
||||
int readfd;
|
||||
unsigned int wantlen, int prngd) {
|
||||
int readfd = -1;
|
||||
unsigned int readcount;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
if (prngd) {
|
||||
#if DROPBEAR_USE_PRNGD
|
||||
if (prngd)
|
||||
{
|
||||
readfd = connect_unix(filename);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
readfd = open(filename, O_RDONLY);
|
||||
}
|
||||
|
||||
@@ -75,58 +70,31 @@ process_file(hash_state *hs, const char *filename,
|
||||
}
|
||||
|
||||
readcount = 0;
|
||||
while (len == 0 || readcount < len)
|
||||
{
|
||||
while (wantlen == 0 || readcount < wantlen) {
|
||||
int readlen, wantread;
|
||||
unsigned char readbuf[4096];
|
||||
if (!already_blocked && !prngd)
|
||||
{
|
||||
int res;
|
||||
struct timeval timeout;
|
||||
fd_set read_fds;
|
||||
|
||||
timeout.tv_sec = 2;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
DROPBEAR_FD_ZERO(&read_fds);
|
||||
FD_SET(readfd, &read_fds);
|
||||
res = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
|
||||
if (res == 0)
|
||||
{
|
||||
dropbear_log(LOG_WARNING, "Warning: Reading the randomness source '%s' seems to have blocked.\nYou may need to find a better entropy source.", filename);
|
||||
already_blocked = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
if (wantlen == 0) {
|
||||
wantread = sizeof(readbuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
wantread = MIN(sizeof(readbuf), len-readcount);
|
||||
} else {
|
||||
wantread = MIN(sizeof(readbuf), wantlen-readcount);
|
||||
}
|
||||
|
||||
#if DROPBEAR_USE_PRNGD
|
||||
if (prngd)
|
||||
{
|
||||
if (prngd) {
|
||||
char egdcmd[2];
|
||||
egdcmd[0] = 0x02; /* blocking read */
|
||||
egdcmd[1] = (unsigned char)wantread;
|
||||
if (write(readfd, egdcmd, 2) < 0)
|
||||
{
|
||||
if (write(readfd, egdcmd, 2) < 0) {
|
||||
dropbear_exit("Can't send command to egd");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
readlen = read(readfd, readbuf, wantread);
|
||||
if (readlen <= 0) {
|
||||
if (readlen < 0 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (readlen == 0 && len == 0)
|
||||
{
|
||||
if (readlen == 0 && wantlen == 0) {
|
||||
/* whole file was read as requested */
|
||||
break;
|
||||
}
|
||||
@@ -193,6 +161,63 @@ void fuzz_seed(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_GETRANDOM
|
||||
/* Reads entropy seed with getrandom().
|
||||
* May block if the kernel isn't ready.
|
||||
* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int process_getrandom(hash_state *hs) {
|
||||
char buf[INIT_SEED_SIZE];
|
||||
ssize_t ret;
|
||||
|
||||
/* First try non-blocking so that we can warn about waiting */
|
||||
ret = getrandom(buf, sizeof(buf), GRND_NONBLOCK);
|
||||
if (ret == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
/* Old kernel */
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
/* Other errors fall through to blocking getrandom() */
|
||||
TRACE(("first getrandom() failed: %d %s", errno, strerror(errno)))
|
||||
if (errno == EAGAIN) {
|
||||
dropbear_log(LOG_WARNING, "Waiting for kernel randomness to be initialised...");
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait blocking if needed. Loop in case we get EINTR */
|
||||
while (ret != sizeof(buf)) {
|
||||
ret = getrandom(buf, sizeof(buf), 0);
|
||||
|
||||
if (ret == sizeof(buf)) {
|
||||
/* Success */
|
||||
break;
|
||||
}
|
||||
if (ret == -1 && errno == EINTR) {
|
||||
/* Try again. */
|
||||
continue;
|
||||
}
|
||||
if (ret >= 0) {
|
||||
TRACE(("Short read %zd from getrandom() shouldn't happen", ret))
|
||||
/* Try again? */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Unexpected problem, fall back to /dev/urandom */
|
||||
TRACE(("2nd getrandom() failed: %d %s", errno, strerror(errno)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == sizeof(buf)) {
|
||||
/* Success, stir in the entropy */
|
||||
sha1_process(hs, (void*)buf, sizeof(buf));
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
return DROPBEAR_FAILURE;
|
||||
|
||||
}
|
||||
#endif /* HAVE_GETRANDOM */
|
||||
|
||||
/* Initialise the prng from /dev/urandom or prngd. This function can
|
||||
* be called multiple times */
|
||||
void seedrandom() {
|
||||
@@ -202,6 +227,7 @@ void seedrandom() {
|
||||
pid_t pid;
|
||||
struct timeval tv;
|
||||
clock_t clockval;
|
||||
int urandom_seeded = 0;
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
@@ -215,21 +241,31 @@ void seedrandom() {
|
||||
/* existing state */
|
||||
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
|
||||
|
||||
#if DROPBEAR_USE_PRNGD
|
||||
if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_PRNGD_SOCKET);
|
||||
}
|
||||
#else
|
||||
/* non-blocking random source (probably /dev/urandom) */
|
||||
if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_URANDOM_DEV);
|
||||
#ifdef HAVE_GETRANDOM
|
||||
if (process_getrandom(&hs) == DROPBEAR_SUCCESS) {
|
||||
urandom_seeded = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!urandom_seeded) {
|
||||
#if DROPBEAR_USE_PRNGD
|
||||
if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_PRNGD_SOCKET);
|
||||
urandom_seeded = 1;
|
||||
}
|
||||
#else
|
||||
/* non-blocking random source (probably /dev/urandom) */
|
||||
if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_URANDOM_DEV);
|
||||
urandom_seeded = 1;
|
||||
}
|
||||
#endif
|
||||
} /* urandom_seeded */
|
||||
|
||||
/* A few other sources to fall back on.
|
||||
* Add more here for other platforms */
|
||||
#ifdef __linux__
|
||||
|
||||
6
debian/changelog
vendored
6
debian/changelog
vendored
@@ -1,3 +1,9 @@
|
||||
dropbear (2020.79-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Mon, 15 Jun 2020 22:51:57 +0800
|
||||
|
||||
dropbear (2019.78-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
10
debug.h
10
debug.h
@@ -43,12 +43,6 @@
|
||||
#define CHECKCLEARTOWRITE()
|
||||
#endif
|
||||
|
||||
/* Define this, compile with -pg and set GMON_OUT_PREFIX=gmon to get gmon
|
||||
* output when Dropbear forks. This will allow it gprof to be used.
|
||||
* It's useful to run dropbear -F, so you don't fork as much */
|
||||
/* (This is Linux specific) */
|
||||
/*#define DEBUG_FORKGPROF*/
|
||||
|
||||
/* A couple of flags, not usually useful, and mightn't do anything */
|
||||
|
||||
/*#define DEBUG_KEXHASH*/
|
||||
@@ -66,7 +60,9 @@ extern int debug_trace;
|
||||
|
||||
/* To debug with GDB it is easier to run with no forking of child processes.
|
||||
You will need to pass "-F" as well. */
|
||||
/* #define DEBUG_NOFORK */
|
||||
#ifndef DEBUG_NOFORK
|
||||
#define DEBUG_NOFORK 0
|
||||
#endif
|
||||
|
||||
|
||||
/* For testing as non-root on shadowed systems, include the crypt of a password
|
||||
|
||||
@@ -22,6 +22,7 @@ IMPORTANT: Some options will require "make clean" after changes */
|
||||
#define DSS_PRIV_FILENAME "/etc/dropbear/dropbear_dss_host_key"
|
||||
#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
|
||||
#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key"
|
||||
#define ED25519_PRIV_FILENAME "/etc/dropbear/dropbear_ed25519_host_key"
|
||||
|
||||
/* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens
|
||||
* on chosen ports and keeps accepting connections. This is the default.
|
||||
@@ -47,7 +48,7 @@ IMPORTANT: Some options will require "make clean" after changes */
|
||||
#define DROPBEAR_SMALL_CODE 1
|
||||
|
||||
/* Enable X11 Forwarding - server only */
|
||||
#define DROPBEAR_X11FWD 1
|
||||
#define DROPBEAR_X11FWD 0
|
||||
|
||||
/* Enable TCP Fowarding */
|
||||
/* 'Local' is "-L" style (client listening port forwarded via server)
|
||||
@@ -82,27 +83,36 @@ IMPORTANT: Some options will require "make clean" after changes */
|
||||
* Including both AES keysize variants (128 and 256) will result in
|
||||
* a minimal size increase */
|
||||
#define DROPBEAR_AES128 1
|
||||
#define DROPBEAR_3DES 1
|
||||
#define DROPBEAR_AES256 1
|
||||
#define DROPBEAR_3DES 0
|
||||
#define DROPBEAR_TWOFISH256 0
|
||||
#define DROPBEAR_TWOFISH128 0
|
||||
/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */
|
||||
#define DROPBEAR_BLOWFISH 0
|
||||
|
||||
/* Enable Chacha20-Poly1305 authenticated encryption mode. This is
|
||||
* generally faster than AES256 on CPU w/o dedicated AES instructions,
|
||||
* having the same key size. Recommended.
|
||||
* Compiling in will add ~5,5kB to binary size on x86-64 */
|
||||
#define DROPBEAR_CHACHA20POLY1305 1
|
||||
|
||||
/* Enable "Counter Mode" for ciphers. Recommended. */
|
||||
#define DROPBEAR_ENABLE_CTR_MODE 1
|
||||
|
||||
/* Enable CBC mode for ciphers. This has security issues though
|
||||
* is the most compatible with older SSH implementations */
|
||||
#define DROPBEAR_ENABLE_CBC_MODE 1
|
||||
may be required for compatibility with old implementations */
|
||||
#define DROPBEAR_ENABLE_CBC_MODE 0
|
||||
|
||||
/* Enable "Counter Mode" for ciphers. This is more secure than
|
||||
* CBC mode against certain attacks. It is recommended for security
|
||||
* and forwards compatibility */
|
||||
#define DROPBEAR_ENABLE_CTR_MODE 1
|
||||
/* Enable "Galois/Counter Mode" for ciphers. This authenticated
|
||||
* encryption mode is combination of CTR mode and GHASH. Recommended
|
||||
* for security and forwards compatibility, but slower than CTR on
|
||||
* CPU w/o dedicated AES/GHASH instructions.
|
||||
* Compiling in will add ~6kB to binary size on x86-64 */
|
||||
#define DROPBEAR_ENABLE_GCM_MODE 0
|
||||
|
||||
/* Message integrity. sha2-256 is recommended as a default,
|
||||
sha1 for compatibility */
|
||||
#define DROPBEAR_SHA1_HMAC 1
|
||||
#define DROPBEAR_SHA1_96_HMAC 1
|
||||
#define DROPBEAR_SHA2_256_HMAC 1
|
||||
#define DROPBEAR_SHA1_96_HMAC 0
|
||||
|
||||
/* Hostkey/public key algorithms - at least one required, these are used
|
||||
* for hostkey as well as for verifying signatures with pubkey auth.
|
||||
@@ -116,11 +126,15 @@ IMPORTANT: Some options will require "make clean" after changes */
|
||||
* code (either ECDSA or ECDH) increases binary size - around 30kB
|
||||
* on x86-64 */
|
||||
#define DROPBEAR_ECDSA 1
|
||||
/* Ed25519 is faster than ECDSA. Compiling in Ed25519 code increases
|
||||
binary size - around 7,5kB on x86-64 */
|
||||
#define DROPBEAR_ED25519 1
|
||||
|
||||
/* RSA must be >=1024 */
|
||||
#define DROPBEAR_DEFAULT_RSA_SIZE 2048
|
||||
/* DSS is always 1024 */
|
||||
/* ECDSA defaults to largest size configured, usually 521 */
|
||||
/* Ed25519 is always 256 */
|
||||
|
||||
/* Add runtime flag "-R" to generate hostkeys as-needed when the first
|
||||
connection using that key type occurs.
|
||||
@@ -143,7 +157,7 @@ IMPORTANT: Some options will require "make clean" after changes */
|
||||
* group14 is supported by most implementations.
|
||||
* group16 provides a greater strength level but is slower and increases binary size
|
||||
* curve25519 and ecdh algorithms are faster than non-elliptic curve methods
|
||||
* curve25519 increases binary size by ~8kB on x86-64
|
||||
* curve25519 increases binary size by ~2,5kB on x86-64
|
||||
* including either ECDH or ECDSA increases binary size by ~30kB on x86-64
|
||||
|
||||
* Small systems should generally include either curve25519 or ecdh for performance.
|
||||
@@ -174,7 +188,7 @@ group1 in Dropbear server too */
|
||||
#define DO_HOST_LOOKUP 0
|
||||
|
||||
/* Whether to print the message of the day (MOTD). */
|
||||
#define DO_MOTD 0
|
||||
#define DO_MOTD 1
|
||||
#define MOTD_FILENAME "/etc/motd"
|
||||
|
||||
/* Authentication Types - at least one required.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "options.h"
|
||||
#include "dh_groups.h"
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
|
||||
#if DROPBEAR_DH_GROUP1
|
||||
/* diffie-hellman-group1-sha1 value for p */
|
||||
const unsigned char dh_p_1[DH_P_1_LEN] = {
|
||||
@@ -92,3 +94,4 @@ const unsigned char dh_p_16[DH_P_16_LEN] = {
|
||||
/* Same for all groups */
|
||||
const int DH_G_VAL = 2;
|
||||
|
||||
#endif /* DROPBEAR_NORMAL_DH */
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#define DROPBEAR_DH_GROUPS_H
|
||||
#include "options.h"
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
|
||||
#if DROPBEAR_DH_GROUP1
|
||||
#define DH_P_1_LEN 128
|
||||
extern const unsigned char dh_p_1[DH_P_1_LEN];
|
||||
@@ -17,8 +19,8 @@ extern const unsigned char dh_p_14[DH_P_14_LEN];
|
||||
extern const unsigned char dh_p_16[DH_P_16_LEN];
|
||||
#endif
|
||||
|
||||
|
||||
extern const int DH_G_VAL;
|
||||
|
||||
#endif /* DROPBEAR_NORMAL_DH */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -107,7 +107,7 @@ Print the version
|
||||
Authorized Keys
|
||||
|
||||
~/.ssh/authorized_keys can be set up to allow remote login with a RSA,
|
||||
ECDSA, or DSS
|
||||
ECDSA, Ed25519 or DSS
|
||||
key. Each line is of the form
|
||||
.TP
|
||||
[restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment]
|
||||
@@ -146,8 +146,8 @@ key authentication.
|
||||
Host Key Files
|
||||
|
||||
Host key files are read at startup from a standard location, by default
|
||||
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key, and
|
||||
/etc/dropbear/dropbear_ecdsa_host_key
|
||||
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key,
|
||||
/etc/dropbear/dropbear_ecdsa_host_key and /etc/dropbear/dropbear_ed25519_host_key
|
||||
|
||||
If the -r command line option is specified the default files are not loaded.
|
||||
Host key files are of the form generated by dropbearkey.
|
||||
|
||||
8
dropbear_lint.sh
Executable file
8
dropbear_lint.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
EXITCODE=0
|
||||
|
||||
# #ifdef instead of #if
|
||||
grep '#ifdef DROPBEAR' -I *.c *.h && EXITCODE=1
|
||||
|
||||
exit $EXITCODE
|
||||
@@ -13,7 +13,7 @@ dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
|
||||
.SH DESCRIPTION
|
||||
.B dropbearkey
|
||||
generates a
|
||||
\fIRSA\fR, \fIDSS\fR, or \fIECDSA\fR
|
||||
\fIRSA\fR, \fIDSS\fR, \fIECDSA\fR, or \fIEd25519\fR
|
||||
format SSH private key, and saves it to a file for the use with the
|
||||
Dropbear client or server.
|
||||
Note that
|
||||
@@ -26,6 +26,7 @@ Type of key to generate.
|
||||
Must be one of
|
||||
.I rsa
|
||||
.I ecdsa
|
||||
.I ed25519
|
||||
or
|
||||
.IR dss .
|
||||
.TP
|
||||
|
||||
@@ -43,6 +43,10 @@
|
||||
* mp_int y
|
||||
* mp_int x
|
||||
*
|
||||
* Ed25519:
|
||||
* string "ssh-ed25519"
|
||||
* string k (32 bytes) + A (32 bytes)
|
||||
*
|
||||
*/
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
@@ -51,6 +55,7 @@
|
||||
|
||||
#include "genrsa.h"
|
||||
#include "gendss.h"
|
||||
#include "gened25519.h"
|
||||
#include "ecdsa.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "dbrandom.h"
|
||||
@@ -75,6 +80,9 @@ static void printhelp(char * progname) {
|
||||
#endif
|
||||
#if DROPBEAR_ECDSA
|
||||
" ecdsa\n"
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
" ed25519\n"
|
||||
#endif
|
||||
"-f filename Use filename for the secret key.\n"
|
||||
" ~/.ssh/id_dropbear is recommended for client keys.\n"
|
||||
@@ -94,6 +102,9 @@ static void printhelp(char * progname) {
|
||||
"521 "
|
||||
#endif
|
||||
"\n"
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
" Ed25519 has a fixed size of 256 bits\n"
|
||||
#endif
|
||||
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
|
||||
#if DEBUG_TRACE
|
||||
@@ -106,6 +117,14 @@ static void printhelp(char * progname) {
|
||||
static void check_signkey_bits(enum signkey_type type, int bits)
|
||||
{
|
||||
switch (type) {
|
||||
#if DROPBEAR_ED25519
|
||||
case DROPBEAR_SIGNKEY_ED25519:
|
||||
if (bits != 256) {
|
||||
dropbear_exit("Ed25519 keys have a fixed size of 256 bits\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
|
||||
@@ -114,7 +133,7 @@ static void check_signkey_bits(enum signkey_type type, int bits)
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPEAR_DSS
|
||||
#if DROPEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
if (bits != 1024) {
|
||||
dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
|
||||
@@ -224,6 +243,12 @@ int main(int argc, char ** argv) {
|
||||
keytype = DROPBEAR_SIGNKEY_ECDSA_KEYGEN;
|
||||
}
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
if (strcmp(typetext, "ed25519") == 0)
|
||||
{
|
||||
keytype = DROPBEAR_SIGNKEY_ED25519;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (keytype == DROPBEAR_SIGNKEY_NONE) {
|
||||
fprintf(stderr, "Unknown key type '%s'\n", typetext);
|
||||
|
||||
13
dss.c
13
dss.c
@@ -284,6 +284,7 @@ void buf_put_dss_sign(buffer* buf, const dropbear_dss_key *key, const buffer *da
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
unsigned int writelen;
|
||||
unsigned int i;
|
||||
size_t written;
|
||||
DEF_MP_INT(dss_k);
|
||||
DEF_MP_INT(dss_m);
|
||||
DEF_MP_INT(dss_temp1);
|
||||
@@ -340,31 +341,31 @@ void buf_put_dss_sign(buffer* buf, const dropbear_dss_key *key, const buffer *da
|
||||
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
|
||||
buf_putint(buf, 2*SHA1_HASH_SIZE);
|
||||
|
||||
writelen = mp_unsigned_bin_size(&dss_r);
|
||||
writelen = mp_ubin_size(&dss_r);
|
||||
dropbear_assert(writelen <= SHA1_HASH_SIZE);
|
||||
/* need to pad to 160 bits with leading zeros */
|
||||
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
|
||||
buf_putbyte(buf, 0);
|
||||
}
|
||||
if (mp_to_unsigned_bin(&dss_r, buf_getwriteptr(buf, writelen))
|
||||
if (mp_to_ubin(&dss_r, buf_getwriteptr(buf, writelen), writelen, &written)
|
||||
!= MP_OKAY) {
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
mp_clear(&dss_r);
|
||||
buf_incrwritepos(buf, writelen);
|
||||
buf_incrwritepos(buf, written);
|
||||
|
||||
writelen = mp_unsigned_bin_size(&dss_s);
|
||||
writelen = mp_ubin_size(&dss_s);
|
||||
dropbear_assert(writelen <= SHA1_HASH_SIZE);
|
||||
/* need to pad to 160 bits with leading zeros */
|
||||
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
|
||||
buf_putbyte(buf, 0);
|
||||
}
|
||||
if (mp_to_unsigned_bin(&dss_s, buf_getwriteptr(buf, writelen))
|
||||
if (mp_to_ubin(&dss_s, buf_getwriteptr(buf, writelen), writelen, &written)
|
||||
!= MP_OKAY) {
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
mp_clear(&dss_s);
|
||||
buf_incrwritepos(buf, writelen);
|
||||
buf_incrwritepos(buf, written);
|
||||
|
||||
mp_clear_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
|
||||
&dss_m, NULL);
|
||||
|
||||
2
dss.h
2
dss.h
@@ -30,7 +30,7 @@
|
||||
|
||||
#if DROPBEAR_DSS
|
||||
|
||||
typedef struct {
|
||||
typedef struct dropbear_DSS_Key {
|
||||
|
||||
mp_int* p;
|
||||
mp_int* q;
|
||||
|
||||
4
ecc.c
4
ecc.c
@@ -166,13 +166,13 @@ ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *c
|
||||
key = new_ecc_key();
|
||||
key->dp = curve->dp;
|
||||
|
||||
if (mp_read_unsigned_bin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
if (mp_from_ubin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
TRACE(("failed to read x"))
|
||||
goto out;
|
||||
}
|
||||
buf_incrpos(buf, size);
|
||||
|
||||
if (mp_read_unsigned_bin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
if (mp_from_ubin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
TRACE(("failed to read y"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
182
ed25519.c
Normal file
182
ed25519.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
/* Perform Ed25519 operations on data, including reading keys, signing and
|
||||
* verification. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "buffer.h"
|
||||
#include "ssh.h"
|
||||
#include "curve25519.h"
|
||||
#include "ed25519.h"
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
|
||||
/* Load a public ed25519 key from a buffer, initialising the values.
|
||||
* The key will have the same format as buf_put_ed25519_key.
|
||||
* These should be freed with ed25519_key_free.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_ed25519_pub_key(buffer *buf, dropbear_ed25519_key *key) {
|
||||
|
||||
unsigned int len;
|
||||
|
||||
TRACE(("enter buf_get_ed25519_pub_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */
|
||||
|
||||
len = buf_getint(buf);
|
||||
if (len != CURVE25519_LEN || buf->len - buf->pos < len) {
|
||||
TRACE(("leave buf_get_ed25519_pub_key: failure"))
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
m_burn(key->priv, CURVE25519_LEN);
|
||||
memcpy(key->pub, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
|
||||
buf_incrpos(buf, CURVE25519_LEN);
|
||||
|
||||
TRACE(("leave buf_get_ed25519_pub_key: success"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Same as buf_get_ed25519_pub_key, but reads private key at the end.
|
||||
* Loads a public and private ed25519 key from a buffer
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_ed25519_priv_key(buffer *buf, dropbear_ed25519_key *key) {
|
||||
|
||||
unsigned int len;
|
||||
|
||||
TRACE(("enter buf_get_ed25519_priv_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */
|
||||
|
||||
len = buf_getint(buf);
|
||||
if (len != CURVE25519_LEN*2 || buf->len - buf->pos < len) {
|
||||
TRACE(("leave buf_get_ed25519_priv_key: failure"))
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
memcpy(key->priv, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
|
||||
buf_incrpos(buf, CURVE25519_LEN);
|
||||
memcpy(key->pub, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
|
||||
buf_incrpos(buf, CURVE25519_LEN);
|
||||
|
||||
TRACE(("leave buf_get_ed25519_pub_key: success"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Clear and free the memory used by a public or private key */
|
||||
void ed25519_key_free(dropbear_ed25519_key *key) {
|
||||
|
||||
TRACE2(("enter ed25519_key_free"))
|
||||
|
||||
if (key == NULL) {
|
||||
TRACE2(("leave ed25519_key_free: key == NULL"))
|
||||
return;
|
||||
}
|
||||
m_burn(key->priv, CURVE25519_LEN);
|
||||
m_free(key);
|
||||
|
||||
TRACE2(("leave rsa_key_free"))
|
||||
}
|
||||
|
||||
/* Put the public ed25519 key into the buffer in the required format */
|
||||
void buf_put_ed25519_pub_key(buffer *buf, const dropbear_ed25519_key *key) {
|
||||
|
||||
TRACE(("enter buf_put_ed25519_pub_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
|
||||
buf_putstring(buf, key->pub, CURVE25519_LEN);
|
||||
|
||||
TRACE(("leave buf_put_ed25519_pub_key"))
|
||||
}
|
||||
|
||||
/* Put the public and private ed25519 key into the buffer in the required format */
|
||||
void buf_put_ed25519_priv_key(buffer *buf, const dropbear_ed25519_key *key) {
|
||||
|
||||
TRACE(("enter buf_put_ed25519_priv_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
|
||||
buf_putint(buf, CURVE25519_LEN*2);
|
||||
buf_putbytes(buf, key->priv, CURVE25519_LEN);
|
||||
buf_putbytes(buf, key->pub, CURVE25519_LEN);
|
||||
|
||||
TRACE(("leave buf_put_ed25519_priv_key"))
|
||||
}
|
||||
|
||||
/* Sign the data presented with key, writing the signature contents
|
||||
* to the buffer */
|
||||
void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const buffer *data_buf) {
|
||||
|
||||
unsigned char s[64];
|
||||
unsigned long slen = sizeof(s);
|
||||
|
||||
TRACE(("enter buf_put_ed25519_sign"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
dropbear_ed25519_sign(data_buf->data, data_buf->len, s, &slen, key->priv, key->pub);
|
||||
buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
|
||||
buf_putstring(buf, s, slen);
|
||||
|
||||
TRACE(("leave buf_put_ed25519_sign"))
|
||||
}
|
||||
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
/* Verify a signature in buf, made on data by the key given.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf) {
|
||||
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
unsigned char *s;
|
||||
unsigned long slen;
|
||||
|
||||
TRACE(("enter buf_ed25519_verify"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
slen = buf_getint(buf);
|
||||
if (slen != 64 || buf->len - buf->pos < slen) {
|
||||
TRACE(("bad size"))
|
||||
goto out;
|
||||
}
|
||||
s = buf_getptr(buf, slen);
|
||||
|
||||
if (dropbear_ed25519_verify(data_buf->data, data_buf->len,
|
||||
s, slen, key->pub) == 0) {
|
||||
/* signature is valid */
|
||||
TRACE(("success!"))
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE(("leave buf_ed25519_verify: ret %d", ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
54
ed25519.h
Normal file
54
ed25519.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef DROPBEAR_ED25519_H_
|
||||
#define DROPBEAR_ED25519_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
|
||||
#define CURVE25519_LEN 32
|
||||
|
||||
typedef struct dropbear_ED25519_Key {
|
||||
|
||||
unsigned char priv[CURVE25519_LEN];
|
||||
unsigned char pub[CURVE25519_LEN];
|
||||
|
||||
} dropbear_ed25519_key;
|
||||
|
||||
void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const buffer *data_buf);
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_ed25519_verify(buffer * buf, const dropbear_ed25519_key *key, const buffer *data_buf);
|
||||
#endif
|
||||
int buf_get_ed25519_pub_key(buffer* buf, dropbear_ed25519_key *key);
|
||||
int buf_get_ed25519_priv_key(buffer* buf, dropbear_ed25519_key *key);
|
||||
void buf_put_ed25519_pub_key(buffer* buf, const dropbear_ed25519_key *key);
|
||||
void buf_put_ed25519_priv_key(buffer* buf, const dropbear_ed25519_key *key);
|
||||
void ed25519_key_free(dropbear_ed25519_key *key);
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
#endif /* DROPBEAR_ED25519_H_ */
|
||||
@@ -99,6 +99,10 @@ rsa.c RSA asymmetric crypto routines
|
||||
|
||||
dss.c DSS asymmetric crypto routines
|
||||
|
||||
ed25519.c Ed25519 asymmetric crypto routines
|
||||
|
||||
gened25519.c Ed25519 key generation
|
||||
|
||||
gendss.c DSS key generation
|
||||
|
||||
genrsa.c RSA key generation
|
||||
|
||||
@@ -112,6 +112,14 @@ static void load_fixed_hostkeys(void) {
|
||||
dropbear_exit("failed fixed ecdsa hostkey");
|
||||
}
|
||||
|
||||
buf_setlen(b, 0);
|
||||
buf_putbytes(b, keyed25519, keyed25519_len);
|
||||
buf_setpos(b, 0);
|
||||
type = DROPBEAR_SIGNKEY_ED25519;
|
||||
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("failed fixed ed25519 hostkey");
|
||||
}
|
||||
|
||||
buf_free(b);
|
||||
}
|
||||
|
||||
@@ -139,7 +147,7 @@ void fuzz_get_socket_address(int UNUSED(fd), char **local_host, char **local_por
|
||||
void fuzz_fake_send_kexdh_reply(void) {
|
||||
assert(!ses.dh_K);
|
||||
m_mp_alloc_init_multi(&ses.dh_K, NULL);
|
||||
mp_set_int(ses.dh_K, 12345678);
|
||||
mp_set_ul(ses.dh_K, 12345678uL);
|
||||
finish_kexhashbuf();
|
||||
}
|
||||
|
||||
|
||||
@@ -127,3 +127,13 @@ unsigned char keyd[] = {
|
||||
0xf9, 0x39
|
||||
};
|
||||
unsigned int keyd_len = 458;
|
||||
unsigned char keyed25519[] = {
|
||||
0x00, 0x00, 0x00, 0x0b, 0x73, 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35,
|
||||
0x35, 0x31, 0x39, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb3, 0x79, 0x06, 0xe5,
|
||||
0x9b, 0xe7, 0xe4, 0x6e, 0xec, 0xfe, 0xa5, 0x39, 0x21, 0x7c, 0xf6, 0x66,
|
||||
0x8c, 0x0b, 0x6a, 0x01, 0x09, 0x05, 0xc7, 0x4f, 0x64, 0xa8, 0x24, 0xd2,
|
||||
0x8d, 0xbd, 0xdd, 0xc6, 0x3c, 0x99, 0x1b, 0x2d, 0x3e, 0x33, 0x90, 0x19,
|
||||
0xa4, 0xd5, 0xe9, 0x23, 0xfe, 0x8e, 0xd6, 0xd4, 0xf9, 0xb1, 0x11, 0x69,
|
||||
0x7c, 0x57, 0x52, 0x0e, 0x41, 0xdb, 0x1b, 0x12, 0x87, 0xfa, 0xc9
|
||||
};
|
||||
unsigned int keyed25519_len = 83;
|
||||
|
||||
72
fuzzer-kexcurve25519.c
Normal file
72
fuzzer-kexcurve25519.c
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "fuzz.h"
|
||||
#include "session.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
#include "debug.h"
|
||||
#include "runopts.h"
|
||||
#include "algo.h"
|
||||
#include "bignum.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
static int once = 0;
|
||||
static struct key_context* keep_newkeys = NULL;
|
||||
/* number of generated parameters is limited by the timeout for the first run.
|
||||
TODO move this to the libfuzzer initialiser function instead if the timeout
|
||||
doesn't apply there */
|
||||
#define NUM_PARAMS 20
|
||||
static struct kex_curve25519_param *curve25519_params[NUM_PARAMS];
|
||||
|
||||
if (!once) {
|
||||
fuzz_common_setup();
|
||||
fuzz_svr_setup();
|
||||
|
||||
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "curve25519-sha256");
|
||||
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ED25519;
|
||||
ses.newkeys = keep_newkeys;
|
||||
|
||||
/* Pre-generate parameters */
|
||||
int i;
|
||||
for (i = 0; i < NUM_PARAMS; i++) {
|
||||
curve25519_params[i] = gen_kexcurve25519_param();
|
||||
}
|
||||
|
||||
once = 1;
|
||||
}
|
||||
|
||||
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_malloc_set_epoch(1);
|
||||
|
||||
if (setjmp(fuzz.jmp) == 0) {
|
||||
/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
|
||||
with DROPBEAR_KEX_CURVE25519 */
|
||||
ses.newkeys = keep_newkeys;
|
||||
|
||||
/* Choose from the collection of curve25519 params */
|
||||
unsigned int e = buf_getint(fuzz.input);
|
||||
struct kex_curve25519_param *curve25519_param = curve25519_params[e % NUM_PARAMS];
|
||||
|
||||
buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
|
||||
|
||||
ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
|
||||
kexcurve25519_comb_key(curve25519_param, ecdh_qs, svr_opts.hostkey);
|
||||
|
||||
mp_clear(ses.dh_K);
|
||||
m_free(ses.dh_K);
|
||||
buf_free(ecdh_qs);
|
||||
|
||||
buf_free(ses.hash);
|
||||
buf_free(ses.session_id);
|
||||
/* kexhashbuf is freed in kexdh_comb_key */
|
||||
|
||||
m_malloc_free_epoch(1, 0);
|
||||
} else {
|
||||
m_malloc_free_epoch(1, 1);
|
||||
TRACE(("dropbear_exit longjmped"))
|
||||
/* dropbear_exit jumped here */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -27,7 +27,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
unsigned int algolen;
|
||||
char* algoname = buf_getstring(keyblob, &algolen);
|
||||
|
||||
if (have_algo(algoname, algolen, sshhostkey) == DROPBEAR_FAILURE) {
|
||||
if (signature_type_from_name(algoname, algolen) == DROPBEAR_SIGNKEY_NONE) {
|
||||
dropbear_exit("fuzzer imagined a bogus algorithm");
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "session.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
#include "debug.h"
|
||||
#include "dss.h"
|
||||
|
||||
static void setup_fuzzer(void) {
|
||||
fuzz_common_setup();
|
||||
@@ -27,21 +28,35 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
|
||||
if (setjmp(fuzz.jmp) == 0) {
|
||||
sign_key *key = new_sign_key();
|
||||
enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
|
||||
if (buf_get_pub_key(fuzz.input, key, &type) == DROPBEAR_SUCCESS) {
|
||||
if (buf_verify(fuzz.input, key, verifydata) == DROPBEAR_SUCCESS) {
|
||||
enum signkey_type keytype = DROPBEAR_SIGNKEY_ANY;
|
||||
if (buf_get_pub_key(fuzz.input, key, &keytype) == DROPBEAR_SUCCESS) {
|
||||
enum signature_type sigtype;
|
||||
if (keytype == DROPBEAR_SIGNKEY_RSA) {
|
||||
/* Flip a coin to decide rsa signature type */
|
||||
int flag = buf_getbyte(fuzz.input);
|
||||
if (flag & 0x01) {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
|
||||
} else {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
}
|
||||
} else {
|
||||
sigtype = signature_type_from_signkey(keytype);
|
||||
}
|
||||
if (buf_verify(fuzz.input, key, sigtype, verifydata) == DROPBEAR_SUCCESS) {
|
||||
/* The fuzzer is capable of generating keys with a signature to match.
|
||||
We don't want false positives if the key is bogus, since a client/server
|
||||
wouldn't be trusting a bogus key anyway */
|
||||
int boguskey = 0;
|
||||
|
||||
if (type == DROPBEAR_SIGNKEY_DSS) {
|
||||
if (keytype == DROPBEAR_SIGNKEY_DSS) {
|
||||
/* So far have seen dss keys with bad p/q/g domain parameters */
|
||||
int pprime, qprime;
|
||||
assert(mp_prime_is_prime(key->dsskey->p, 5, &pprime) == MP_OKAY);
|
||||
assert(mp_prime_is_prime(key->dsskey->q, 18, &qprime) == MP_OKAY);
|
||||
boguskey = !(pprime && qprime);
|
||||
/* Could also check g**q mod p == 1 */
|
||||
int pprime, qprime, trials;
|
||||
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->p));
|
||||
assert(mp_prime_is_prime(key->dsskey->p, trials, &pprime) == MP_OKAY);
|
||||
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->q));
|
||||
assert(mp_prime_is_prime(key->dsskey->q, trials, &qprime) == MP_OKAY);
|
||||
boguskey = !(pprime && qprime);
|
||||
/* Could also check g**q mod p == 1 */
|
||||
}
|
||||
|
||||
if (!boguskey) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
result=0
|
||||
|
||||
hg clone https://secure.ucc.asn.au/hg/dropbear-fuzzcorpus fuzzcorpus || exit 1
|
||||
test -d fuzzcorpus && hg --repository fuzzcorpus/ pull || hg clone https://secure.ucc.asn.au/hg/dropbear-fuzzcorpus fuzzcorpus || exit 1
|
||||
for f in `make list-fuzz-targets`; do
|
||||
./$f fuzzcorpus/$f/* || result=1
|
||||
done
|
||||
|
||||
120
gcm.c
Normal file
120
gcm.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2020 by Vladislav Grishenko
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
#include "dbutil.h"
|
||||
#include "gcm.h"
|
||||
|
||||
#if DROPBEAR_ENABLE_GCM_MODE
|
||||
|
||||
#define GHASH_LEN 16
|
||||
|
||||
static const struct dropbear_hash dropbear_ghash =
|
||||
{NULL, 0, GHASH_LEN};
|
||||
|
||||
static int dropbear_gcm_start(int cipher, const unsigned char *IV,
|
||||
const unsigned char *key, int keylen,
|
||||
int UNUSED(num_rounds), dropbear_gcm_state *state) {
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_gcm_start"))
|
||||
|
||||
if ((err = gcm_init(&state->gcm, cipher, key, keylen)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
memcpy(state->iv, IV, GCM_NONCE_LEN);
|
||||
|
||||
TRACE2(("leave dropbear_gcm_start"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int dropbear_gcm_crypt(unsigned int UNUSED(seq),
|
||||
const unsigned char *in, unsigned char *out,
|
||||
unsigned long len, unsigned long taglen,
|
||||
dropbear_gcm_state *state, int direction) {
|
||||
unsigned char *iv, tag[GHASH_LEN];
|
||||
int i, err;
|
||||
|
||||
TRACE2(("enter dropbear_gcm_crypt"))
|
||||
|
||||
if (len < 4 || taglen != GHASH_LEN) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
gcm_reset(&state->gcm);
|
||||
|
||||
if ((err = gcm_add_iv(&state->gcm,
|
||||
state->iv, GCM_NONCE_LEN)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = gcm_add_aad(&state->gcm, in, 4)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = gcm_process(&state->gcm, (unsigned char *) in + 4,
|
||||
len - 4, out + 4, direction)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (direction == LTC_ENCRYPT) {
|
||||
gcm_done(&state->gcm, out + len, &taglen);
|
||||
} else {
|
||||
gcm_done(&state->gcm, tag, &taglen);
|
||||
if (constant_time_memcmp(in + len, tag, taglen) != 0) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* increment invocation counter */
|
||||
iv = state->iv + GCM_IVFIX_LEN;
|
||||
for (i = GCM_IVCTR_LEN - 1; i >= 0 && ++iv[i] == 0; i--);
|
||||
|
||||
TRACE2(("leave dropbear_gcm_crypt"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int dropbear_gcm_getlength(unsigned int UNUSED(seq),
|
||||
const unsigned char *in, unsigned int *outlen,
|
||||
unsigned long len, dropbear_gcm_state* UNUSED(state)) {
|
||||
TRACE2(("enter dropbear_gcm_getlength"))
|
||||
|
||||
if (len < 4) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
LOAD32H(*outlen, in);
|
||||
|
||||
TRACE2(("leave dropbear_gcm_getlength"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
const struct dropbear_cipher_mode dropbear_mode_gcm =
|
||||
{(void *)dropbear_gcm_start, NULL, NULL,
|
||||
(void *)dropbear_gcm_crypt,
|
||||
(void *)dropbear_gcm_getlength, &dropbear_ghash};
|
||||
|
||||
#endif /* DROPBEAR_ENABLE_GCM_MODE */
|
||||
47
gcm.h
Normal file
47
gcm.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2020 by Vladislav Grishenko
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef DROPBEAR_DROPBEAR_GCM_H_
|
||||
#define DROPBEAR_DROPBEAR_GCM_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
|
||||
#if DROPBEAR_ENABLE_GCM_MODE
|
||||
|
||||
#define GCM_IVFIX_LEN 4
|
||||
#define GCM_IVCTR_LEN 8
|
||||
#define GCM_NONCE_LEN (GCM_IVFIX_LEN + GCM_IVCTR_LEN)
|
||||
|
||||
typedef struct {
|
||||
gcm_state gcm;
|
||||
unsigned char iv[GCM_NONCE_LEN];
|
||||
} dropbear_gcm_state;
|
||||
|
||||
extern const struct dropbear_cipher_mode dropbear_mode_gcm;
|
||||
|
||||
#endif /* DROPBEAR_ENABLE_GCM_MODE */
|
||||
|
||||
#endif /* DROPBEAR_DROPBEAR_GCM_H_ */
|
||||
13
gendss.c
13
gendss.c
@@ -68,6 +68,7 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
|
||||
static void getq(const dropbear_dss_key *key) {
|
||||
|
||||
unsigned char buf[QSIZE];
|
||||
int trials;
|
||||
|
||||
/* 160 bit prime */
|
||||
genrandom(buf, QSIZE);
|
||||
@@ -76,8 +77,9 @@ static void getq(const dropbear_dss_key *key) {
|
||||
|
||||
bytes_to_mp(key->q, buf, QSIZE);
|
||||
|
||||
/* 18 rounds are required according to HAC */
|
||||
if (mp_prime_next_prime(key->q, 18, 0) != MP_OKAY) {
|
||||
/* ask FIPS 186.4 how many Rabin-Miller trials are required */
|
||||
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->q));
|
||||
if (mp_prime_next_prime(key->q, trials, 0) != MP_OKAY) {
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -89,7 +91,7 @@ static void getp(const dropbear_dss_key *key, unsigned int size) {
|
||||
DEF_MP_INT(tempC);
|
||||
DEF_MP_INT(tempP);
|
||||
DEF_MP_INT(temp2q);
|
||||
int result;
|
||||
int result, trials;
|
||||
unsigned char *buf;
|
||||
|
||||
m_mp_init_multi(&tempX, &tempC, &tempP, &temp2q, NULL);
|
||||
@@ -129,9 +131,10 @@ static void getp(const dropbear_dss_key *key, unsigned int size) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* now check for prime, 5 rounds is enough according to HAC */
|
||||
/* ask FIPS 186.4 how many Rabin-Miller trials are required */
|
||||
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->p));
|
||||
/* result == 1 => p is prime */
|
||||
if (mp_prime_is_prime(key->p, 5, &result) != MP_OKAY) {
|
||||
if (mp_prime_is_prime(key->p, trials, &result) != MP_OKAY) {
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
47
gened25519.c
Normal file
47
gened25519.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "dbrandom.h"
|
||||
#include "curve25519.h"
|
||||
#include "gened25519.h"
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
|
||||
dropbear_ed25519_key * gen_ed25519_priv_key(unsigned int size) {
|
||||
|
||||
dropbear_ed25519_key *key;
|
||||
|
||||
if (size != 256) {
|
||||
dropbear_exit("Ed25519 keys have a fixed size of 256 bits");
|
||||
}
|
||||
|
||||
key = m_malloc(sizeof(*key));
|
||||
dropbear_ed25519_make_key(key->pub, key->priv);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
36
gened25519.h
Normal file
36
gened25519.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef DROPBEAR_GENED25519_H_
|
||||
#define DROPBEAR_GENED25519_H_
|
||||
|
||||
#include "ed25519.h"
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
|
||||
dropbear_ed25519_key * gen_ed25519_priv_key(unsigned int size);
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
#endif /* DROPBEAR_GENED25519_H_ */
|
||||
11
genrsa.c
11
genrsa.c
@@ -53,10 +53,7 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
|
||||
m_mp_alloc_init_multi(&key->e, &key->n, &key->d, &key->p, &key->q, NULL);
|
||||
m_mp_init_multi(&pminus, &lcm, &qminus, NULL);
|
||||
|
||||
if (mp_set_int(key->e, RSA_E) != MP_OKAY) {
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
mp_set_ul(key->e, RSA_E);
|
||||
|
||||
while (1) {
|
||||
getrsaprime(key->p, &pminus, key->e, size/16);
|
||||
@@ -95,6 +92,7 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
mp_int* rsa_e, unsigned int size_bytes) {
|
||||
|
||||
unsigned char *buf;
|
||||
int trials;
|
||||
DEF_MP_INT(temp_gcd);
|
||||
|
||||
buf = (unsigned char*)m_malloc(size_bytes);
|
||||
@@ -108,8 +106,9 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
|
||||
bytes_to_mp(prime, buf, size_bytes);
|
||||
|
||||
/* find the next integer which is prime, 8 round of miller-rabin */
|
||||
if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) {
|
||||
/* find the next integer which is prime */
|
||||
trials = mp_prime_rabin_miller_trials(mp_count_bits(prime));
|
||||
if (mp_prime_next_prime(prime, trials, 0) != MP_OKAY) {
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
43
gensignkey.c
43
gensignkey.c
@@ -4,18 +4,26 @@
|
||||
#include "ecdsa.h"
|
||||
#include "genrsa.h"
|
||||
#include "gendss.h"
|
||||
#include "gened25519.h"
|
||||
#include "signkey.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int buf_writefile(buffer * buf, const char * filename) {
|
||||
static int buf_writefile(buffer * buf, const char * filename, int skip_exist) {
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
int fd = -1;
|
||||
|
||||
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
|
||||
filename, strerror(errno));
|
||||
/* If generating keys on connection (skip_exist) it's OK to get EEXIST
|
||||
- we probably just lost a race with another connection to generate the key */
|
||||
if (skip_exist && errno == EEXIST) {
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
} else {
|
||||
dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
|
||||
filename, strerror(errno));
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -68,6 +76,10 @@ static int get_default_bits(enum signkey_type keytype)
|
||||
return 384;
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
|
||||
return 256;
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
case DROPBEAR_SIGNKEY_ED25519:
|
||||
return 256;
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
@@ -118,6 +130,11 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
|
||||
*signkey_key_ptr(key, keytype) = ecckey;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
case DROPBEAR_SIGNKEY_ED25519:
|
||||
key->ed25519key = gen_ed25519_priv_key(bits);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
dropbear_exit("Internal error");
|
||||
@@ -134,7 +151,7 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
|
||||
|
||||
fn_temp = m_malloc(strlen(filename) + 30);
|
||||
snprintf(fn_temp, strlen(filename)+30, "%s.tmp%d", filename, getpid());
|
||||
ret = buf_writefile(buf, fn_temp);
|
||||
ret = buf_writefile(buf, fn_temp, 0);
|
||||
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
goto out;
|
||||
@@ -144,14 +161,24 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
|
||||
/* If generating keys on connection (skipexist) it's OK to get EEXIST
|
||||
- we probably just lost a race with another connection to generate the key */
|
||||
if (!(skip_exist && errno == EEXIST)) {
|
||||
dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename,
|
||||
strerror(errno));
|
||||
/* XXX fallback to non-atomic copy for some filesystems? */
|
||||
ret = DROPBEAR_FAILURE;
|
||||
if (errno == EPERM || errno == EACCES) {
|
||||
/* Non-atomic fallback when hard-links not allowed or unsupported */
|
||||
buf_setpos(buf, 0);
|
||||
ret = buf_writefile(buf, filename, skip_exist);
|
||||
} else {
|
||||
dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename,
|
||||
strerror(errno));
|
||||
ret = DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* ensure directory update is flushed to disk, otherwise we can end up
|
||||
with zero-byte hostkey files if the power goes off */
|
||||
fsync_parent_dir(filename);
|
||||
|
||||
out:
|
||||
if (buf) {
|
||||
buf_burn(buf);
|
||||
|
||||
@@ -124,6 +124,10 @@
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_RANDOM_H
|
||||
#include <sys/random.h>
|
||||
#endif
|
||||
|
||||
#ifdef BUNDLED_LIBTOM
|
||||
#include "libtomcrypt/src/headers/tomcrypt.h"
|
||||
#include "libtommath/tommath.h"
|
||||
@@ -164,6 +168,10 @@ typedef u_int32_t uint32_t;
|
||||
#include <linux/pkt_sched.h>
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_PLUGIN
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include "fake-rfc2553.h"
|
||||
|
||||
#include "fuzz.h"
|
||||
|
||||
12
kex.h
12
kex.h
@@ -36,10 +36,12 @@ void recv_msg_newkeys(void);
|
||||
void kexfirstinitialise(void);
|
||||
void finish_kexhashbuf(void);
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
struct kex_dh_param *gen_kexdh_param(void);
|
||||
void free_kexdh_param(struct kex_dh_param *param);
|
||||
void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
|
||||
sign_key *hostkey);
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_ECDH
|
||||
struct kex_ecdh_param *gen_kexecdh_param(void);
|
||||
@@ -65,6 +67,8 @@ void recv_msg_kexdh_init(void); /* server */
|
||||
void send_msg_kexdh_init(void); /* client */
|
||||
void recv_msg_kexdh_reply(void); /* client */
|
||||
|
||||
void recv_msg_ext_info(void);
|
||||
|
||||
struct KEXState {
|
||||
|
||||
unsigned sentkexinit : 1; /*set when we've sent/recv kexinit packet */
|
||||
@@ -73,8 +77,9 @@ struct KEXState {
|
||||
unsigned sentnewkeys : 1; /* set once we've send MSG_NEWKEYS (will be cleared once we have also received */
|
||||
unsigned recvnewkeys : 1; /* set once we've received MSG_NEWKEYS (cleared once we have also sent */
|
||||
|
||||
unsigned donefirstkex : 1; /* Set to 1 after the first kex has completed,
|
||||
unsigned int donefirstkex; /* Set to 1 after the first kex has completed,
|
||||
ie the transport layer has been set up */
|
||||
unsigned int donesecondkex; /* Set to 1 after the second kex has completed */
|
||||
|
||||
unsigned our_first_follows_matches : 1;
|
||||
|
||||
@@ -84,10 +89,12 @@ struct KEXState {
|
||||
|
||||
};
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
struct kex_dh_param {
|
||||
mp_int pub; /* e */
|
||||
mp_int priv; /* x */
|
||||
};
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_ECDH
|
||||
struct kex_ecdh_param {
|
||||
@@ -101,9 +108,6 @@ struct kex_curve25519_param {
|
||||
unsigned char priv[CURVE25519_LEN];
|
||||
unsigned char pub[CURVE25519_LEN];
|
||||
};
|
||||
|
||||
/* No header file for curve25519_donna */
|
||||
int curve25519_donna(unsigned char *out, const unsigned char *secret, const unsigned char *other);
|
||||
#endif
|
||||
|
||||
#endif /* DROPBEAR_KEX_H_ */
|
||||
|
||||
172
keyimport.c
172
keyimport.c
@@ -35,6 +35,18 @@
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "ecc.h"
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
#include "dss.h"
|
||||
#include "ed25519.h"
|
||||
|
||||
static const unsigned char OSSH_PKEY_BLOB[] =
|
||||
"openssh-key-v1\0" /* AUTH_MAGIC */
|
||||
"\0\0\0\4none" /* cipher name*/
|
||||
"\0\0\0\4none" /* kdf name */
|
||||
"\0\0\0\0" /* kdf */
|
||||
"\0\0\0\1"; /* key num */
|
||||
#define OSSH_PKEY_BLOBLEN (sizeof(OSSH_PKEY_BLOB) - 1)
|
||||
|
||||
#if DROPBEAR_ECDSA
|
||||
static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
|
||||
@@ -352,7 +364,7 @@ struct mpint_pos { void *start; int bytes; };
|
||||
* Code to read and write OpenSSH private keys.
|
||||
*/
|
||||
|
||||
enum { OSSH_DSA, OSSH_RSA, OSSH_EC };
|
||||
enum { OSSH_DSA, OSSH_RSA, OSSH_EC, OSSH_PKEY };
|
||||
struct openssh_key {
|
||||
int type;
|
||||
int encrypted;
|
||||
@@ -364,11 +376,12 @@ struct openssh_key {
|
||||
static struct openssh_key *load_openssh_key(const char *filename)
|
||||
{
|
||||
struct openssh_key *ret;
|
||||
buffer *buf = NULL;
|
||||
FILE *fp = NULL;
|
||||
char buffer[256];
|
||||
char *errmsg = NULL, *p = NULL;
|
||||
int headers_done;
|
||||
unsigned long len, outlen;
|
||||
unsigned long len;
|
||||
|
||||
ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key));
|
||||
ret->keyblob = NULL;
|
||||
@@ -397,12 +410,15 @@ static struct openssh_key *load_openssh_key(const char *filename)
|
||||
ret->type = OSSH_DSA;
|
||||
else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n"))
|
||||
ret->type = OSSH_EC;
|
||||
else if (!strcmp(buffer, "-----BEGIN OPENSSH PRIVATE KEY-----\n"))
|
||||
ret->type = OSSH_PKEY;
|
||||
else {
|
||||
errmsg = "Unrecognised key type";
|
||||
goto error;
|
||||
}
|
||||
|
||||
headers_done = 0;
|
||||
buf = buf_new(0);
|
||||
while (1) {
|
||||
if (!fgets(buffer, sizeof(buffer), fp)) {
|
||||
errmsg = "Unexpected end of file";
|
||||
@@ -448,22 +464,33 @@ static struct openssh_key *load_openssh_key(const char *filename)
|
||||
} else {
|
||||
headers_done = 1;
|
||||
len = strlen(buffer);
|
||||
outlen = len*4/3;
|
||||
if (ret->keyblob_len + outlen > ret->keyblob_size) {
|
||||
ret->keyblob_size = ret->keyblob_len + outlen + 256;
|
||||
ret->keyblob = (unsigned char*)m_realloc(ret->keyblob,
|
||||
ret->keyblob_size);
|
||||
}
|
||||
outlen = ret->keyblob_size - ret->keyblob_len;
|
||||
if (base64_decode((const unsigned char *)buffer, len,
|
||||
ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){
|
||||
errmsg = "Error decoding base64";
|
||||
goto error;
|
||||
}
|
||||
ret->keyblob_len += outlen;
|
||||
buf = buf_resize(buf, buf->size + len);
|
||||
buf_putbytes(buf, buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (buf && buf->len) {
|
||||
ret->keyblob_size = ret->keyblob_len + buf->len*4/3 + 256;
|
||||
ret->keyblob = (unsigned char*)m_realloc(ret->keyblob, ret->keyblob_size);
|
||||
len = ret->keyblob_size;
|
||||
if (base64_decode((const unsigned char *)buf->data, buf->len,
|
||||
ret->keyblob, &len) != CRYPT_OK){
|
||||
errmsg = "Error decoding base64";
|
||||
goto error;
|
||||
}
|
||||
ret->keyblob_len = len;
|
||||
}
|
||||
|
||||
if (ret->type == OSSH_PKEY) {
|
||||
if (ret->keyblob_len < OSSH_PKEY_BLOBLEN ||
|
||||
memcmp(ret->keyblob, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN)) {
|
||||
errmsg = "Error decoding OpenSSH key";
|
||||
goto error;
|
||||
}
|
||||
ret->keyblob_len -= OSSH_PKEY_BLOBLEN;
|
||||
memmove(ret->keyblob, ret->keyblob + OSSH_PKEY_BLOBLEN, ret->keyblob_len);
|
||||
}
|
||||
|
||||
if (ret->keyblob_len == 0 || !ret->keyblob) {
|
||||
errmsg = "Key body not present";
|
||||
goto error;
|
||||
@@ -474,10 +501,18 @@ static struct openssh_key *load_openssh_key(const char *filename)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
buf_burn(buf);
|
||||
buf_free(buf);
|
||||
}
|
||||
m_burn(buffer, sizeof(buffer));
|
||||
return ret;
|
||||
|
||||
error:
|
||||
if (buf) {
|
||||
buf_burn(buf);
|
||||
buf_free(buf);
|
||||
}
|
||||
m_burn(buffer, sizeof(buffer));
|
||||
if (ret) {
|
||||
if (ret->keyblob) {
|
||||
@@ -569,6 +604,57 @@ static sign_key *openssh_read(const char *filename, const char * UNUSED(passphra
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we have a decrypted key blob, which contains OpenSSH
|
||||
* encoded private key. We must now untangle the OpenSSH format.
|
||||
*/
|
||||
if (key->type == OSSH_PKEY) {
|
||||
blobbuf = buf_new(key->keyblob_len);
|
||||
buf_putbytes(blobbuf, key->keyblob, key->keyblob_len);
|
||||
buf_setpos(blobbuf, 0);
|
||||
|
||||
/* limit length of private key blob */
|
||||
len = buf_getint(blobbuf);
|
||||
buf_setlen(blobbuf, blobbuf->pos + len);
|
||||
|
||||
type = DROPBEAR_SIGNKEY_ANY;
|
||||
if (buf_get_pub_key(blobbuf, retkey, &type)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
errmsg = "Error parsing OpenSSH key";
|
||||
goto ossh_error;
|
||||
}
|
||||
|
||||
/* restore full length */
|
||||
buf_setlen(blobbuf, key->keyblob_len);
|
||||
|
||||
if (type != DROPBEAR_SIGNKEY_NONE) {
|
||||
retkey->type = type;
|
||||
/* limit length of private key blob */
|
||||
len = buf_getint(blobbuf);
|
||||
buf_setlen(blobbuf, blobbuf->pos + len);
|
||||
#if DROPBEAR_ED25519
|
||||
if (type == DROPBEAR_SIGNKEY_ED25519) {
|
||||
buf_incrpos(blobbuf, 8);
|
||||
buf_eatstring(blobbuf);
|
||||
buf_eatstring(blobbuf);
|
||||
buf_incrpos(blobbuf, -SSH_SIGNKEY_ED25519_LEN-4);
|
||||
if (buf_get_ed25519_priv_key(blobbuf, retkey->ed25519key)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
errmsg = NULL;
|
||||
retval = retkey;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
errmsg = "Unsupported OpenSSH key type";
|
||||
ossh_error:
|
||||
sign_key_free(retkey);
|
||||
retkey = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we have a decrypted key blob, which contains an ASN.1
|
||||
* encoded private key. We must now untangle the ASN.1.
|
||||
@@ -781,7 +867,7 @@ static sign_key *openssh_read(const char *filename, const char * UNUSED(passphra
|
||||
goto error;
|
||||
}
|
||||
m_mp_alloc_init_multi((mp_int**)&ecc->k, NULL);
|
||||
if (mp_read_unsigned_bin(ecc->k, private_key_bytes, private_key_len)
|
||||
if (mp_from_ubin(ecc->k, private_key_bytes, private_key_len)
|
||||
!= MP_OKAY) {
|
||||
errmsg = "Error parsing ECC key";
|
||||
goto error;
|
||||
@@ -1056,6 +1142,7 @@ static int openssh_write(const char *filename, sign_key *key,
|
||||
unsigned long pubkey_size = 2*curve_size+1;
|
||||
int k_size;
|
||||
int err = 0;
|
||||
size_t written;
|
||||
|
||||
/* version. less than 10 bytes */
|
||||
buf_incrwritepos(seq_buf,
|
||||
@@ -1063,12 +1150,14 @@ static int openssh_write(const char *filename, sign_key *key,
|
||||
buf_putbyte(seq_buf, 1);
|
||||
|
||||
/* privateKey */
|
||||
k_size = mp_unsigned_bin_size((*eck)->k);
|
||||
k_size = mp_ubin_size((*eck)->k);
|
||||
dropbear_assert(k_size <= curve_size);
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 4, k_size, 0));
|
||||
mp_to_unsigned_bin((*eck)->k, buf_getwriteptr(seq_buf, k_size));
|
||||
buf_incrwritepos(seq_buf, k_size);
|
||||
if (mp_to_ubin((*eck)->k, buf_getwriteptr(seq_buf, k_size), k_size, &written) != MP_OKAY) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
buf_incrwritepos(seq_buf, written);
|
||||
|
||||
/* SECGCurveNames */
|
||||
switch (key->type)
|
||||
@@ -1129,6 +1218,51 @@ static int openssh_write(const char *filename, sign_key *key,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
if (key->type == DROPBEAR_SIGNKEY_ED25519) {
|
||||
buffer *buf = buf_new(300);
|
||||
keyblob = buf_new(100);
|
||||
extrablob = buf_new(200);
|
||||
|
||||
/* private key blob w/o header */
|
||||
buf_put_priv_key(keyblob, key, key->type);
|
||||
buf_setpos(keyblob, 0);
|
||||
buf_incrpos(keyblob, buf_getint(keyblob));
|
||||
len = buf_getint(keyblob);
|
||||
|
||||
/* header */
|
||||
buf_putbytes(buf, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN);
|
||||
|
||||
/* public key */
|
||||
buf_put_pub_key(buf, key, key->type);
|
||||
|
||||
/* private key */
|
||||
buf_incrwritepos(extrablob, 4);
|
||||
buf_put_pub_key(extrablob, key, key->type);
|
||||
buf_putstring(extrablob, buf_getptr(keyblob, len), len);
|
||||
/* comment */
|
||||
buf_putstring(extrablob, "", 0);
|
||||
/* padding to cipher block length */
|
||||
len = (extrablob->len+8) & ~7;
|
||||
for (i = 1; len - extrablob->len > 0; i++)
|
||||
buf_putbyte(extrablob, i);
|
||||
buf_setpos(extrablob, 0);
|
||||
buf_putbytes(extrablob, "\0\0\0\0\0\0\0\0", 8);
|
||||
buf_putbufstring(buf, extrablob);
|
||||
|
||||
outlen = len = pos = buf->len;
|
||||
outblob = (unsigned char*)m_malloc(outlen);
|
||||
memcpy(outblob, buf->data, buf->len);
|
||||
|
||||
buf_burn(buf);
|
||||
buf_free(buf);
|
||||
buf = NULL;
|
||||
|
||||
header = "-----BEGIN OPENSSH PRIVATE KEY-----\n";
|
||||
footer = "-----END OPENSSH PRIVATE KEY-----\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Padding on OpenSSH keys is deterministic. The number of
|
||||
* padding bytes is always more than zero, and always at most
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
July 1st, 2018
|
||||
v1.18.2
|
||||
-- Fix Side Channel Based ECDSA Key Extraction (CVE-2018-12437) (PR #408)
|
||||
-- Fix potential stack overflow when DER flexi-decoding (CVE-2018-0739) (PR #373)
|
||||
-- Fix two-key 3DES (PR #390)
|
||||
-- Fix accelerated CTR mode (PR #359)
|
||||
-- Fix Fortuna PRNG (PR #363)
|
||||
-- Fix compilation on platforms where cc doesn't point to gcc (PR #382)
|
||||
-- Fix using the wrong environment variable LT instead of LIBTOOL (PR #392)
|
||||
-- Fix build on platforms where the compiler provides __WCHAR_MAX__ but wchar.h is not available (PR #390)
|
||||
-- Fix & re-factor crypt_list_all_sizes() and crypt_list_all_constants() (PR #414)
|
||||
-- Minor fixes (PR's #350 #351 #375 #377 #378 #379)
|
||||
|
||||
January 22nd, 2018
|
||||
v1.18.1
|
||||
-- Fix wrong SHA3 blocksizes, thanks to Claus Fischer for reporting this via Mail (PR #329)
|
||||
|
||||
@@ -65,9 +65,10 @@ int main(int argc, char **argv)
|
||||
/* get and print the length of the names (and values) list */
|
||||
if (crypt_list_all_constants(NULL, &names_list_len) != 0) exit(EXIT_FAILURE);
|
||||
/* get and print the names (and values) list */
|
||||
names_list = malloc(names_list_len);
|
||||
if ((names_list = malloc(names_list_len)) == NULL) exit(EXIT_FAILURE);
|
||||
if (crypt_list_all_constants(names_list, &names_list_len) != 0) exit(EXIT_FAILURE);
|
||||
printf("%s\n", names_list);
|
||||
free(names_list);
|
||||
}
|
||||
} else if (argc == 3) {
|
||||
if (strcmp(argv[1], "-s") == 0) {
|
||||
|
||||
@@ -42,9 +42,10 @@ int main(int argc, char **argv)
|
||||
printf(" need to allocate %u bytes \n\n", sizes_list_len);
|
||||
|
||||
/* get and print the names (and sizes) list */
|
||||
sizes_list = malloc(sizes_list_len);
|
||||
if ((sizes_list = malloc(sizes_list_len)) == NULL) exit(EXIT_FAILURE);
|
||||
if (crypt_list_all_sizes(sizes_list, &sizes_list_len) != 0) exit(EXIT_FAILURE);
|
||||
printf(" supported sizes:\n\n%s\n\n", sizes_list);
|
||||
free(sizes_list);
|
||||
} else if (argc == 2) {
|
||||
if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
|
||||
char* base = strdup(basename(argv[0]));
|
||||
@@ -60,9 +61,10 @@ int main(int argc, char **argv)
|
||||
/* get and print the length of the names (and sizes) list */
|
||||
if (crypt_list_all_sizes(NULL, &sizes_list_len) != 0) exit(EXIT_FAILURE);
|
||||
/* get and print the names (and sizes) list */
|
||||
sizes_list = malloc(sizes_list_len);
|
||||
if ((sizes_list = malloc(sizes_list_len)) == NULL) exit(EXIT_FAILURE);
|
||||
if (crypt_list_all_sizes(sizes_list, &sizes_list_len) != 0) exit(EXIT_FAILURE);
|
||||
printf("%s\n", sizes_list);
|
||||
free(sizes_list);
|
||||
}
|
||||
} else if (argc == 3) {
|
||||
if (strcmp(argv[1], "-s") == 0) {
|
||||
|
||||
@@ -466,7 +466,7 @@ static void time_cipher_lrw(void)
|
||||
tally_results(1);
|
||||
}
|
||||
#else
|
||||
static void time_cipher_lrw(void) { fprintf(stderr, "NO LRW\n"); return 0; }
|
||||
static void time_cipher_lrw(void) { fprintf(stderr, "NO LRW\n"); }
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ void cipher_gen(void)
|
||||
printf("keysize error: %s\n", error_to_string(err));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (kl == lastkl) break;
|
||||
if (kl == lastkl) continue;
|
||||
lastkl = kl;
|
||||
fprintf(out, "Key Size: %d bytes\n", kl);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = LibTomCrypt
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER=1.18.1
|
||||
PROJECT_NUMBER=1.18.2
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
@@ -3666,11 +3666,15 @@ key, and any hash that produces at least a 256--bit output. However, to make th
|
||||
it has been fixed to those choices.
|
||||
|
||||
Fortuna is more secure than Yarrow in the sense that attackers who learn parts of the entropy being
|
||||
added to the PRNG learn far less about the state than that of Yarrow. Without getting into to many
|
||||
added to the PRNG learn far less about the state than that of Yarrow. Without getting into too many
|
||||
details Fortuna has the ability to recover from state determination attacks where the attacker starts
|
||||
to learn information from the PRNGs output about the internal state. Yarrow on the other hand, cannot
|
||||
recover from that problem until new entropy is added to the pool and put to use through the ready() function.
|
||||
|
||||
For detailed information on how the algorithm works and what you have to do to maintain the secure state
|
||||
get a copy of the book\footnote{Niels Ferguson and Bruce Schneier, Practical Cryptography. ISBN 0-471-22357-3.} or
|
||||
read the paper online\footnote{\url{https://www.schneier.com/academic/paperfiles/fortuna.pdf} [Accessed on 7th Dec. 2017]}.
|
||||
|
||||
\subsubsection{RC4}
|
||||
|
||||
RC4 is an old stream cipher that can also double duty as a PRNG in a pinch. You key RC4 by
|
||||
|
||||
@@ -27,7 +27,7 @@ EXTRALIBS = -L../libtommath -ltommath
|
||||
#Compilation flags
|
||||
LTC_CFLAGS = -Isrc/headers -Itests -DLTC_SOURCE $(CFLAGS)
|
||||
LTC_LDFLAGS = $(LDFLAGS) $(EXTRALIBS)
|
||||
VERSION=1.18.1
|
||||
VERSION=1.18.2
|
||||
|
||||
#Libraries to be created
|
||||
LIBMAIN_S =libtomcrypt.a
|
||||
|
||||
@@ -22,7 +22,7 @@ EXTRALIBS = ../libtommath/tommath.lib
|
||||
#Compilation flags
|
||||
LTC_CFLAGS = /nologo /Isrc/headers/ /Itests/ /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_DEPRECATE /DLTC_SOURCE /W3 $(CFLAGS)
|
||||
LTC_LDFLAGS = advapi32.lib $(EXTRALIBS)
|
||||
VERSION=1.18.1
|
||||
VERSION=1.18.2
|
||||
|
||||
#Libraries to be created (this makefile builds only static libraries)
|
||||
LIBMAIN_S =tomcrypt.lib
|
||||
|
||||
@@ -16,19 +16,19 @@
|
||||
|
||||
PLATFORM := $(shell uname | sed -e 's/_.*//')
|
||||
|
||||
ifndef LT
|
||||
ifndef LIBTOOL
|
||||
ifeq ($(PLATFORM), Darwin)
|
||||
LT:=glibtool
|
||||
LIBTOOL:=glibtool
|
||||
else
|
||||
LT:=libtool
|
||||
LIBTOOL:=libtool
|
||||
endif
|
||||
endif
|
||||
ifeq ($(PLATFORM), CYGWIN)
|
||||
NO_UNDEFINED:=-no-undefined
|
||||
endif
|
||||
LTCOMPILE = $(LT) --mode=compile --tag=CC $(CC)
|
||||
INSTALL_CMD = $(LT) --mode=install install
|
||||
UNINSTALL_CMD = $(LT) --mode=uninstall rm
|
||||
LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC)
|
||||
INSTALL_CMD = $(LIBTOOL) --mode=install install
|
||||
UNINSTALL_CMD = $(LIBTOOL) --mode=uninstall rm
|
||||
|
||||
#Output filenames for various targets.
|
||||
ifndef LIBNAME
|
||||
@@ -49,15 +49,15 @@ src/ciphers/aes/aes_enc.o: src/ciphers/aes/aes.c src/ciphers/aes/aes_tab.c
|
||||
LOBJECTS = $(OBJECTS:.o=.lo)
|
||||
|
||||
$(LIBNAME): $(OBJECTS)
|
||||
$(LT) --mode=link --tag=CC $(CC) $(LTC_CFLAGS) $(CPPFLAGS) $(LTC_LDFLAGS) $(LOBJECTS) $(EXTRALIBS) -o $@ -rpath $(LIBPATH) -version-info $(VERSION_LT) $(NO_UNDEFINED)
|
||||
$(LIBTOOL) --mode=link --tag=CC $(CC) $(LTC_LDFLAGS) $(LOBJECTS) $(EXTRALIBS) -o $@ -rpath $(LIBPATH) -version-info $(VERSION_LT) $(NO_UNDEFINED)
|
||||
|
||||
test: $(call print-help,test,Builds the library and the 'test' application to run all self-tests) $(LIBNAME) $(TOBJECTS)
|
||||
$(LT) --mode=link --tag=CC $(CC) $(LTC_CFLAGS) $(CPPFLAGS) $(LTC_LDFLAGS) -o $(TEST) $(TOBJECTS) $(LIBNAME) $(EXTRALIBS)
|
||||
$(LIBTOOL) --mode=link --tag=CC $(CC) $(LTC_LDFLAGS) -o $(TEST) $(TOBJECTS) $(LIBNAME) $(EXTRALIBS)
|
||||
|
||||
# build the demos from a template
|
||||
define DEMO_template
|
||||
$(1): $(call print-help,$(1),Builds the library and the '$(1)' demo) demos/$(1).o $$(LIBNAME)
|
||||
$$(LT) --mode=link --tag=CC $$(CC) $$(LTC_CFLAGS) $$(CPPFLAGS) $$(LTC_LDFLAGS) $$^ $$(EXTRALIBS) -o $(1)
|
||||
$$(LIBTOOL) --mode=link --tag=CC $$(CC) $$(LTC_LDFLAGS) $$^ $$(EXTRALIBS) -o $(1)
|
||||
endef
|
||||
|
||||
$(foreach demo, $(strip $(DEMOS)), $(eval $(call DEMO_template,$(demo))))
|
||||
|
||||
@@ -39,7 +39,7 @@ EXTRALIBS = ../libtommath/libtommath.a
|
||||
#Compilation flags
|
||||
LTC_CFLAGS = -Isrc/headers -Itests -DLTC_SOURCE $(CFLAGS)
|
||||
LTC_LDFLAGS = $(LDFLAGS) $(EXTRALIBS)
|
||||
VERSION=1.18.1
|
||||
VERSION=1.18.2
|
||||
|
||||
#Libraries to be created (this makefile builds only static libraries)
|
||||
LIBMAIN_S =libtomcrypt.a
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
# (GNU make only)
|
||||
|
||||
# The version - BEWARE: VERSION, VERSION_PC and VERSION_LT are updated via ./updatemakes.sh
|
||||
VERSION=1.18.1
|
||||
VERSION_PC=1.18.1
|
||||
VERSION=1.18.2
|
||||
VERSION_PC=1.18.2
|
||||
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
VERSION_LT=1:1
|
||||
|
||||
@@ -13,9 +13,23 @@ ifndef CROSS_COMPILE
|
||||
CROSS_COMPILE:=
|
||||
endif
|
||||
|
||||
ifeq ($(CC),cc)
|
||||
CC := $(CROSS_COMPILE)gcc
|
||||
# We only need to go through this dance of determining the right compiler if we're using
|
||||
# cross compilation, otherwise $(CC) is fine as-is.
|
||||
ifneq (,$(CROSS_COMPILE))
|
||||
ifeq ($(origin CC),default)
|
||||
CSTR := "\#ifdef __clang__\nCLANG\n\#endif\n"
|
||||
ifeq ($(PLATFORM),FreeBSD)
|
||||
# XXX: FreeBSD needs extra escaping for some reason
|
||||
CSTR := $$$(CSTR)
|
||||
endif
|
||||
ifneq (,$(shell echo $(CSTR) | $(CC) -E - | grep CLANG))
|
||||
CC := $(CROSS_COMPILE)clang
|
||||
else
|
||||
CC := $(CROSS_COMPILE)gcc
|
||||
endif # Clang
|
||||
endif # cc is Make's default
|
||||
endif # CROSS_COMPILE non-empty
|
||||
|
||||
LD:=$(CROSS_COMPILE)ld
|
||||
AR:=$(CROSS_COMPILE)ar
|
||||
|
||||
@@ -24,7 +38,12 @@ AR:=$(CROSS_COMPILE)ar
|
||||
ARFLAGS:=r
|
||||
|
||||
ifndef MAKE
|
||||
MAKE:=make
|
||||
# BSDs refer to GNU Make as gmake
|
||||
ifneq (,$(findstring $(PLATFORM),FreeBSD OpenBSD DragonFly NetBSD))
|
||||
MAKE=gmake
|
||||
else
|
||||
MAKE=make
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef INSTALL_CMD
|
||||
@@ -389,7 +408,7 @@ doc/crypt.pdf: $(call print-help,doc/crypt.pdf,Builds the Developer Manual)
|
||||
$(MAKE) -C doc/ crypt.pdf V=$(V)
|
||||
|
||||
|
||||
install_all: $(call print-help,install_all,Install everything - library bins docs tests) install install_bins install_docs install_test
|
||||
install_all: $(call print-help,install_all,Install everything - library bins docs tests) install install_bins install_docs
|
||||
|
||||
INSTALL_OPTS ?= -m 644
|
||||
|
||||
|
||||
@@ -1434,6 +1434,58 @@ Key Size: 8 bytes
|
||||
|
||||
|
||||
Cipher: 3des
|
||||
Key Size: 16 bytes
|
||||
0: DF0B6C9C31CD0CE4
|
||||
1: 9B3503FDF249920B
|
||||
2: 653924639C39E7FF
|
||||
3: 6A29E0A7F42025BB
|
||||
4: 1628B719BC875D20
|
||||
5: 7D77004A18D0C0B2
|
||||
6: 4D21684EFE962DC1
|
||||
7: B6BD7F82B648A364
|
||||
8: 1F87ABAD83D19E96
|
||||
9: 3DF3533220C3CDED
|
||||
10: D0E7D0ABFBA68747
|
||||
11: 109FE5B38D74E6C9
|
||||
12: AE12C4B4D523784F
|
||||
13: 953CD7F264166764
|
||||
14: 70B3A87D72FA0A22
|
||||
15: 9C9D09AC66AB8F6D
|
||||
16: 4A15AEACB35B76F0
|
||||
17: EFA32F95623BCF1A
|
||||
18: 679901F7737E195C
|
||||
19: 221BB06209DDFCF4
|
||||
20: 0889A953C60BB1BF
|
||||
21: 88F2249380E2D5D9
|
||||
22: 5AB26168B7FA24D5
|
||||
23: 934229150997D390
|
||||
24: 535E4F4C4DA97062
|
||||
25: 03E8D711AC2B8154
|
||||
26: CB5EF6E72EA3EC49
|
||||
27: 9278A864F488C94A
|
||||
28: CB91B77401DAF004
|
||||
29: 4D0BA1C9794E0099
|
||||
30: 9CFA24A21F48043F
|
||||
31: BB6B3A33AEEC01F4
|
||||
32: F2A8566E0FF6033D
|
||||
33: E6AC213000E955E6
|
||||
34: 91F5FF42BBE0B81B
|
||||
35: 6506D72ADEA70E12
|
||||
36: F9BD8C0506C7CC4E
|
||||
37: 89CD85D1C98439ED
|
||||
38: 409410E3E7D66B10
|
||||
39: 4CA64F96F4F3D216
|
||||
40: 383D18FBF8C006BC
|
||||
41: 3806A8CB006EC243
|
||||
42: EE73C06D903D2FCF
|
||||
43: 624BFD3FAD7ED9EB
|
||||
44: 1B5457F2731FB5D1
|
||||
45: 4EC4632DFAC9D5D6
|
||||
46: 8F0B3100FAD612C5
|
||||
47: F955FCAD55AC6C90
|
||||
48: BEB5F023BD413960
|
||||
49: BDC369F3288ED754
|
||||
|
||||
Key Size: 24 bytes
|
||||
0: 58ED248F77F6B19E
|
||||
1: DA5C39983FD34F30
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
/* AES implementation by Tom St Denis
|
||||
*
|
||||
* Derived from the Public Domain source code by
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
* rijndael-alg-fst.c
|
||||
*
|
||||
* @version 3.0 (December 2000)
|
||||
@@ -26,13 +26,13 @@
|
||||
/**
|
||||
@file aes.c
|
||||
Implementation of AES
|
||||
*/
|
||||
*/
|
||||
|
||||
#include "tomcrypt.h"
|
||||
|
||||
#ifdef LTC_RIJNDAEL
|
||||
|
||||
#ifndef ENCRYPT_ONLY
|
||||
#ifndef ENCRYPT_ONLY
|
||||
|
||||
#define SETUP rijndael_setup
|
||||
#define ECB_ENC rijndael_ecb_encrypt
|
||||
@@ -125,20 +125,20 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
|
||||
ulong32 temp, *rk;
|
||||
#ifndef ENCRYPT_ONLY
|
||||
ulong32 *rrk;
|
||||
#endif
|
||||
#endif
|
||||
LTC_ARGCHK(key != NULL);
|
||||
LTC_ARGCHK(skey != NULL);
|
||||
|
||||
|
||||
if (keylen != 16 && keylen != 24 && keylen != 32) {
|
||||
return CRYPT_INVALID_KEYSIZE;
|
||||
}
|
||||
|
||||
|
||||
if (num_rounds != 0 && num_rounds != (10 + ((keylen/8)-2)*2)) {
|
||||
return CRYPT_INVALID_ROUNDS;
|
||||
}
|
||||
|
||||
|
||||
skey->rijndael.Nr = 10 + ((keylen/8)-2)*2;
|
||||
|
||||
|
||||
/* setup the forward key */
|
||||
i = 0;
|
||||
rk = skey->rijndael.eK;
|
||||
@@ -163,7 +163,7 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
|
||||
LOAD32H(rk[5], key + 20);
|
||||
for (;;) {
|
||||
#ifdef _MSC_VER
|
||||
temp = skey->rijndael.eK[rk - skey->rijndael.eK + 5];
|
||||
temp = skey->rijndael.eK[rk - skey->rijndael.eK + 5];
|
||||
#else
|
||||
temp = rk[5];
|
||||
#endif
|
||||
@@ -185,7 +185,7 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
|
||||
LOAD32H(rk[7], key + 28);
|
||||
for (;;) {
|
||||
#ifdef _MSC_VER
|
||||
temp = skey->rijndael.eK[rk - skey->rijndael.eK + 7];
|
||||
temp = skey->rijndael.eK[rk - skey->rijndael.eK + 7];
|
||||
#else
|
||||
temp = rk[7];
|
||||
#endif
|
||||
@@ -209,11 +209,11 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
#ifndef ENCRYPT_ONLY
|
||||
#ifndef ENCRYPT_ONLY
|
||||
/* setup the inverse key now */
|
||||
rk = skey->rijndael.dK;
|
||||
rrk = skey->rijndael.eK + (28 + keylen) - 4;
|
||||
|
||||
|
||||
/* apply the inverse MixColumn transform to all round keys but the first and the last: */
|
||||
/* copy first */
|
||||
*rk++ = *rrk++;
|
||||
@@ -221,11 +221,11 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
|
||||
*rk++ = *rrk++;
|
||||
*rk = *rrk;
|
||||
rk -= 3; rrk -= 3;
|
||||
|
||||
|
||||
for (i = 1; i < skey->rijndael.Nr; i++) {
|
||||
rrk -= 4;
|
||||
rk += 4;
|
||||
#ifdef LTC_SMALL_CODE
|
||||
#ifdef LTC_SMALL_CODE
|
||||
temp = rrk[0];
|
||||
rk[0] = setup_mix2(temp);
|
||||
temp = rrk[1];
|
||||
@@ -259,8 +259,8 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
|
||||
Tks1[byte(temp, 2)] ^
|
||||
Tks2[byte(temp, 1)] ^
|
||||
Tks3[byte(temp, 0)];
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* copy last */
|
||||
@@ -272,7 +272,7 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
|
||||
*rk = *rrk;
|
||||
#endif /* ENCRYPT_ONLY */
|
||||
|
||||
return CRYPT_OK;
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,21 +283,21 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
#ifdef LTC_CLEAN_STACK
|
||||
static int _rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
|
||||
static int _rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
|
||||
#else
|
||||
int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
|
||||
#endif
|
||||
{
|
||||
ulong32 s0, s1, s2, s3, t0, t1, t2, t3, *rk;
|
||||
int Nr, r;
|
||||
|
||||
|
||||
LTC_ARGCHK(pt != NULL);
|
||||
LTC_ARGCHK(ct != NULL);
|
||||
LTC_ARGCHK(skey != NULL);
|
||||
|
||||
|
||||
Nr = skey->rijndael.Nr;
|
||||
rk = skey->rijndael.eK;
|
||||
|
||||
|
||||
/*
|
||||
* map byte array block to cipher state
|
||||
* and add initial round key:
|
||||
@@ -335,7 +335,7 @@ int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
|
||||
Te2(byte(s1, 1)) ^
|
||||
Te3(byte(s2, 0)) ^
|
||||
rk[3];
|
||||
if (r == Nr-2) {
|
||||
if (r == Nr-2) {
|
||||
break;
|
||||
}
|
||||
s0 = t0; s1 = t1; s2 = t2; s3 = t3;
|
||||
@@ -436,7 +436,7 @@ int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
|
||||
(Te4_3[byte(t3, 3)]) ^
|
||||
(Te4_2[byte(t0, 2)]) ^
|
||||
(Te4_1[byte(t1, 1)]) ^
|
||||
(Te4_0[byte(t2, 0)]) ^
|
||||
(Te4_0[byte(t2, 0)]) ^
|
||||
rk[3];
|
||||
STORE32H(s3, ct+12);
|
||||
|
||||
@@ -444,7 +444,7 @@ int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
|
||||
}
|
||||
|
||||
#ifdef LTC_CLEAN_STACK
|
||||
int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
|
||||
int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
|
||||
{
|
||||
int err = _rijndael_ecb_encrypt(pt, ct, skey);
|
||||
burn_stack(sizeof(unsigned long)*8 + sizeof(unsigned long*) + sizeof(int)*2);
|
||||
@@ -452,17 +452,17 @@ int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ENCRYPT_ONLY
|
||||
#ifndef ENCRYPT_ONLY
|
||||
|
||||
/**
|
||||
Decrypts a block of text with AES
|
||||
@param ct The input ciphertext (16 bytes)
|
||||
@param pt The output plaintext (16 bytes)
|
||||
@param skey The key as scheduled
|
||||
@param skey The key as scheduled
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
#ifdef LTC_CLEAN_STACK
|
||||
static int _rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
|
||||
static int _rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
|
||||
#else
|
||||
int ECB_DEC(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
|
||||
#endif
|
||||
@@ -473,7 +473,7 @@ int ECB_DEC(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
|
||||
LTC_ARGCHK(pt != NULL);
|
||||
LTC_ARGCHK(ct != NULL);
|
||||
LTC_ARGCHK(skey != NULL);
|
||||
|
||||
|
||||
Nr = skey->rijndael.Nr;
|
||||
rk = skey->rijndael.dK;
|
||||
|
||||
@@ -514,13 +514,13 @@ int ECB_DEC(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
|
||||
Td3(byte(s0, 0)) ^
|
||||
rk[3];
|
||||
if (r == Nr-2) {
|
||||
break;
|
||||
break;
|
||||
}
|
||||
s0 = t0; s1 = t1; s2 = t2; s3 = t3;
|
||||
}
|
||||
rk += 4;
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
/*
|
||||
* Nr - 1 full rounds:
|
||||
@@ -624,7 +624,7 @@ int ECB_DEC(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
|
||||
|
||||
|
||||
#ifdef LTC_CLEAN_STACK
|
||||
int ECB_DEC(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
|
||||
int ECB_DEC(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
|
||||
{
|
||||
int err = _rijndael_ecb_decrypt(ct, pt, skey);
|
||||
burn_stack(sizeof(unsigned long)*8 + sizeof(unsigned long*) + sizeof(int)*2);
|
||||
@@ -640,51 +640,51 @@ int ECB_TEST(void)
|
||||
{
|
||||
#ifndef LTC_TEST
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
#else
|
||||
int err;
|
||||
static const struct {
|
||||
int keylen;
|
||||
unsigned char key[32], pt[16], ct[16];
|
||||
} tests[] = {
|
||||
{ 16,
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
|
||||
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
|
||||
{ 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30,
|
||||
{ 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30,
|
||||
0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a }
|
||||
}, {
|
||||
}, {
|
||||
24,
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 },
|
||||
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
|
||||
{ 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0,
|
||||
{ 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0,
|
||||
0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91 }
|
||||
}, {
|
||||
32,
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
|
||||
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
|
||||
{ 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf,
|
||||
{ 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf,
|
||||
0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 }
|
||||
}
|
||||
};
|
||||
|
||||
symmetric_key key;
|
||||
unsigned char tmp[2][16];
|
||||
int i, y;
|
||||
|
||||
for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
|
||||
|
||||
symmetric_key key;
|
||||
unsigned char tmp[2][16];
|
||||
int i, y;
|
||||
|
||||
for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
|
||||
zeromem(&key, sizeof(key));
|
||||
if ((err = rijndael_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) {
|
||||
if ((err = rijndael_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
rijndael_ecb_encrypt(tests[i].pt, tmp[0], &key);
|
||||
rijndael_ecb_decrypt(tmp[0], tmp[1], &key);
|
||||
if (compare_testvector(tmp[0], 16, tests[i].ct, 16, "AES Encrypt", i) ||
|
||||
@@ -692,20 +692,20 @@ int ECB_TEST(void)
|
||||
return CRYPT_FAIL_TESTVECTOR;
|
||||
}
|
||||
|
||||
/* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
|
||||
for (y = 0; y < 16; y++) tmp[0][y] = 0;
|
||||
for (y = 0; y < 1000; y++) rijndael_ecb_encrypt(tmp[0], tmp[0], &key);
|
||||
for (y = 0; y < 1000; y++) rijndael_ecb_decrypt(tmp[0], tmp[0], &key);
|
||||
for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
|
||||
}
|
||||
return CRYPT_OK;
|
||||
/* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
|
||||
for (y = 0; y < 16; y++) tmp[0][y] = 0;
|
||||
for (y = 0; y < 1000; y++) rijndael_ecb_encrypt(tmp[0], tmp[0], &key);
|
||||
for (y = 0; y < 1000; y++) rijndael_ecb_decrypt(tmp[0], tmp[0], &key);
|
||||
for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
|
||||
}
|
||||
return CRYPT_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* ENCRYPT_ONLY */
|
||||
|
||||
|
||||
/** Terminate the context
|
||||
/** Terminate the context
|
||||
@param skey The scheduled key
|
||||
*/
|
||||
void ECB_DONE(symmetric_key *skey)
|
||||
|
||||
@@ -94,7 +94,7 @@ static const ulong32 TE0[256] = {
|
||||
0x7bb0b0cbUL, 0xa85454fcUL, 0x6dbbbbd6UL, 0x2c16163aUL,
|
||||
};
|
||||
|
||||
#ifndef PELI_TAB
|
||||
#if !defined(PELI_TAB) && defined(LTC_SMALL_CODE)
|
||||
static const ulong32 Te4[256] = {
|
||||
0x63636363UL, 0x7c7c7c7cUL, 0x77777777UL, 0x7b7b7b7bUL,
|
||||
0xf2f2f2f2UL, 0x6b6b6b6bUL, 0x6f6f6f6fUL, 0xc5c5c5c5UL,
|
||||
@@ -1017,11 +1017,13 @@ static const ulong32 Tks3[] = {
|
||||
|
||||
#endif /* SMALL CODE */
|
||||
|
||||
#ifndef PELI_TAB
|
||||
static const ulong32 rcon[] = {
|
||||
0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL,
|
||||
0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL,
|
||||
0x1B000000UL, 0x36000000UL, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* __LTC_AES_TAB_C__ */
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,9 +7,9 @@
|
||||
* guarantee it works.
|
||||
*/
|
||||
|
||||
/**
|
||||
/**
|
||||
@file twofish.c
|
||||
Implementation of Twofish by Tom St Denis
|
||||
Implementation of Twofish by Tom St Denis
|
||||
*/
|
||||
#include "tomcrypt.h"
|
||||
|
||||
@@ -145,14 +145,14 @@ static ulong32 gf_mult(ulong32 a, ulong32 b, ulong32 p)
|
||||
result = P[0] = B[0] = 0;
|
||||
|
||||
/* unrolled branchless GF multiplier */
|
||||
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
|
||||
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
|
||||
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
|
||||
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
|
||||
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
|
||||
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
|
||||
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
|
||||
result ^= B[a&1];
|
||||
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
|
||||
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
|
||||
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
|
||||
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
|
||||
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
|
||||
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
|
||||
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
|
||||
result ^= B[a&1];
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -243,7 +243,7 @@ static void h_func(const unsigned char *in, unsigned char *out, unsigned char *M
|
||||
unsigned char y[4];
|
||||
for (x = 0; x < 4; x++) {
|
||||
y[x] = in[x];
|
||||
}
|
||||
}
|
||||
switch (k) {
|
||||
case 4:
|
||||
y[0] = (unsigned char)(sbox(1, (ulong32)y[0]) ^ M[4 * (6 + offset) + 0]);
|
||||
@@ -439,7 +439,7 @@ int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetri
|
||||
/* small ram variant */
|
||||
switch (k) {
|
||||
case 4 : skey->twofish.start = 0; break;
|
||||
case 3 : skey->twofish.start = 1; break;
|
||||
case 3 : skey->twofish.start = 1; break;
|
||||
default: skey->twofish.start = 2; break;
|
||||
}
|
||||
#endif
|
||||
@@ -473,18 +473,18 @@ int twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ke
|
||||
int r;
|
||||
#if !defined(LTC_TWOFISH_SMALL) && !defined(__GNUC__)
|
||||
ulong32 *S1, *S2, *S3, *S4;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
LTC_ARGCHK(pt != NULL);
|
||||
LTC_ARGCHK(ct != NULL);
|
||||
LTC_ARGCHK(skey != NULL);
|
||||
|
||||
|
||||
#if !defined(LTC_TWOFISH_SMALL) && !defined(__GNUC__)
|
||||
S1 = skey->twofish.S[0];
|
||||
S2 = skey->twofish.S[1];
|
||||
S3 = skey->twofish.S[2];
|
||||
S4 = skey->twofish.S[3];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
LOAD32L(a,&pt[0]); LOAD32L(b,&pt[4]);
|
||||
LOAD32L(c,&pt[8]); LOAD32L(d,&pt[12]);
|
||||
@@ -492,20 +492,20 @@ int twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ke
|
||||
b ^= skey->twofish.K[1];
|
||||
c ^= skey->twofish.K[2];
|
||||
d ^= skey->twofish.K[3];
|
||||
|
||||
|
||||
k = skey->twofish.K + 8;
|
||||
for (r = 8; r != 0; --r) {
|
||||
t2 = g1_func(b, skey);
|
||||
t1 = g_func(a, skey) + t2;
|
||||
c = RORc(c ^ (t1 + k[0]), 1);
|
||||
d = ROLc(d, 1) ^ (t2 + t1 + k[1]);
|
||||
|
||||
|
||||
t2 = g1_func(d, skey);
|
||||
t1 = g_func(c, skey) + t2;
|
||||
a = RORc(a ^ (t1 + k[2]), 1);
|
||||
b = ROLc(b, 1) ^ (t2 + t1 + k[3]);
|
||||
k += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* output with "undo last swap" */
|
||||
ta = c ^ skey->twofish.K[4];
|
||||
@@ -533,7 +533,7 @@ int twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ke
|
||||
Decrypts a block of text with Twofish
|
||||
@param ct The input ciphertext (16 bytes)
|
||||
@param pt The output plaintext (16 bytes)
|
||||
@param skey The key as scheduled
|
||||
@param skey The key as scheduled
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
#ifdef LTC_CLEAN_STACK
|
||||
@@ -546,18 +546,18 @@ int twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_ke
|
||||
int r;
|
||||
#if !defined(LTC_TWOFISH_SMALL) && !defined(__GNUC__)
|
||||
ulong32 *S1, *S2, *S3, *S4;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
LTC_ARGCHK(pt != NULL);
|
||||
LTC_ARGCHK(ct != NULL);
|
||||
LTC_ARGCHK(skey != NULL);
|
||||
|
||||
|
||||
#if !defined(LTC_TWOFISH_SMALL) && !defined(__GNUC__)
|
||||
S1 = skey->twofish.S[0];
|
||||
S2 = skey->twofish.S[1];
|
||||
S3 = skey->twofish.S[2];
|
||||
S4 = skey->twofish.S[3];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* load input */
|
||||
LOAD32L(ta,&ct[0]); LOAD32L(tb,&ct[4]);
|
||||
@@ -588,7 +588,7 @@ int twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_ke
|
||||
b ^= skey->twofish.K[1];
|
||||
c ^= skey->twofish.K[2];
|
||||
d ^= skey->twofish.K[3];
|
||||
|
||||
|
||||
/* store */
|
||||
STORE32L(a, &pt[0]); STORE32L(b, &pt[4]);
|
||||
STORE32L(c, &pt[8]); STORE32L(d, &pt[12]);
|
||||
@@ -612,8 +612,8 @@ int twofish_test(void)
|
||||
{
|
||||
#ifndef LTC_TEST
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
static const struct {
|
||||
#else
|
||||
static const struct {
|
||||
int keylen;
|
||||
unsigned char key[32], pt[16], ct[16];
|
||||
} tests[] = {
|
||||
@@ -633,7 +633,7 @@ int twofish_test(void)
|
||||
0x85, 0xB6, 0xDC, 0x07, 0x3C, 0xA3, 0x41, 0xB2 },
|
||||
{ 0x18, 0x2B, 0x02, 0xD8, 0x14, 0x97, 0xEA, 0x45,
|
||||
0xF9, 0xDA, 0xAC, 0xDC, 0x29, 0x19, 0x3A, 0x65 }
|
||||
}, {
|
||||
}, {
|
||||
32,
|
||||
{ 0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46,
|
||||
0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D,
|
||||
@@ -647,11 +647,11 @@ int twofish_test(void)
|
||||
};
|
||||
|
||||
|
||||
symmetric_key key;
|
||||
unsigned char tmp[2][16];
|
||||
int err, i, y;
|
||||
|
||||
for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
|
||||
symmetric_key key;
|
||||
unsigned char tmp[2][16];
|
||||
int err, i, y;
|
||||
|
||||
for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
|
||||
if ((err = twofish_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
@@ -661,17 +661,17 @@ int twofish_test(void)
|
||||
compare_testvector(tmp[1], 16, tests[i].pt, 16, "Twofish Decrypt", i) != 0) {
|
||||
return CRYPT_FAIL_TESTVECTOR;
|
||||
}
|
||||
/* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
|
||||
for (y = 0; y < 16; y++) tmp[0][y] = 0;
|
||||
for (y = 0; y < 1000; y++) twofish_ecb_encrypt(tmp[0], tmp[0], &key);
|
||||
for (y = 0; y < 1000; y++) twofish_ecb_decrypt(tmp[0], tmp[0], &key);
|
||||
for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
|
||||
}
|
||||
return CRYPT_OK;
|
||||
#endif
|
||||
/* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
|
||||
for (y = 0; y < 16; y++) tmp[0][y] = 0;
|
||||
for (y = 0; y < 1000; y++) twofish_ecb_encrypt(tmp[0], tmp[0], &key);
|
||||
for (y = 0; y < 1000; y++) twofish_ecb_decrypt(tmp[0], tmp[0], &key);
|
||||
for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
|
||||
}
|
||||
return CRYPT_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Terminate the context
|
||||
/** Terminate the context
|
||||
@param skey The scheduled key
|
||||
*/
|
||||
void twofish_done(symmetric_key *skey)
|
||||
|
||||
@@ -52,7 +52,7 @@ int ccm_memory(int cipher,
|
||||
int err;
|
||||
unsigned long len, L, x, y, z, CTRlen;
|
||||
#ifdef LTC_FAST
|
||||
LTC_FAST_TYPE fastMask = ~0; /* initialize fastMask at all zeroes */
|
||||
LTC_FAST_TYPE fastMask = ~(LTC_FAST_TYPE)0; /* initialize fastMask at all zeroes */
|
||||
#endif
|
||||
unsigned char mask = 0xff; /* initialize mask at all zeroes */
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "tomcrypt.h"
|
||||
|
||||
#ifndef LTC_NO_FILE
|
||||
/**
|
||||
/**
|
||||
@file hash_file.c
|
||||
Hash a file, Tom St Denis
|
||||
*/
|
||||
@@ -34,7 +34,7 @@ int hash_file(int hash, const char *fname, unsigned char *out, unsigned long *ou
|
||||
}
|
||||
|
||||
in = fopen(fname, "rb");
|
||||
if (in == NULL) {
|
||||
if (in == NULL) {
|
||||
return CRYPT_FILE_NOTFOUND;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
Hash open files, Tom St Denis
|
||||
*/
|
||||
|
||||
/**
|
||||
Hash data from an open file handle.
|
||||
/**
|
||||
Hash data from an open file handle.
|
||||
@param hash The index of the hash you want to use
|
||||
@param in The FILE* handle of the file you want to hash
|
||||
@param out [out] The destination of the digest
|
||||
@param outlen [in/out] The max size and resulting size of the digest
|
||||
@result CRYPT_OK if successful
|
||||
@result CRYPT_OK if successful
|
||||
*/
|
||||
int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
@@ -57,8 +57,8 @@ int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outle
|
||||
}
|
||||
} while (x == LTC_FILE_READ_BUFSIZE);
|
||||
if ((err = hash_descriptor[hash].done(&md, out)) == CRYPT_OK) {
|
||||
*outlen = hash_descriptor[hash].hashsize;
|
||||
}
|
||||
*outlen = hash_descriptor[hash].hashsize;
|
||||
}
|
||||
|
||||
LBL_CLEANBUF:
|
||||
zeromem(buf, LTC_FILE_READ_BUFSIZE);
|
||||
|
||||
@@ -27,14 +27,15 @@ extern "C" {
|
||||
|
||||
/* version */
|
||||
#define CRYPT 0x0118
|
||||
#define SCRYPT "1.18.1"
|
||||
#define SCRYPT "1.18.2"
|
||||
|
||||
/* max size of either a cipher/hash block or symmetric key [largest of the two] */
|
||||
#define MAXBLOCKSIZE 128
|
||||
|
||||
#ifndef TAB_SIZE
|
||||
/* descriptor table size */
|
||||
/* Dropbear change - this should be smaller, saves some size */
|
||||
#define TAB_SIZE 5
|
||||
#define TAB_SIZE 32
|
||||
#endif
|
||||
|
||||
/* error codes [will be expanded in future releases] */
|
||||
enum {
|
||||
|
||||
@@ -45,7 +45,7 @@ void crypt_argchk(const char *v, const char *s, int d) NORETURN;
|
||||
|
||||
#elif ARGTYPE == 3
|
||||
|
||||
#define LTC_ARGCHK(x)
|
||||
#define LTC_ARGCHK(x)
|
||||
#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
|
||||
|
||||
#elif ARGTYPE == 4
|
||||
|
||||
@@ -74,8 +74,8 @@
|
||||
#define LTC_NO_MODES
|
||||
#define LTC_NO_HASHES
|
||||
#define LTC_NO_MACS
|
||||
#define LTC_NO_PRNGS
|
||||
#define LTC_NO_PK
|
||||
#define LTC_NO_PRNGS
|
||||
#define LTC_NO_PK
|
||||
#define LTC_NO_PKCS
|
||||
#define LTC_NO_MISC
|
||||
#endif /* LTC_NOTHING */
|
||||
@@ -480,6 +480,13 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(LTC_DER)
|
||||
#ifndef LTC_DER_MAX_RECURSION
|
||||
/* Maximum recursion limit when processing nested ASN.1 types. */
|
||||
#define LTC_DER_MAX_RECURSION 30
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(LTC_MECC) || defined(LTC_MRSA) || defined(LTC_MDSA) || defined(LTC_MKAT)
|
||||
/* Include the MPI functionality? (required by the PK algorithms) */
|
||||
#define LTC_MPI
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
#define LTC_SMALL_CODE
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_BLOWFISH
|
||||
#define LTC_BLOWFISH
|
||||
#endif
|
||||
/* Fewer entries needed */
|
||||
#define TAB_SIZE 5
|
||||
|
||||
#if DROPBEAR_AES
|
||||
#define LTC_RIJNDAEL
|
||||
#endif
|
||||
@@ -27,7 +27,7 @@
|
||||
#define LTC_DES
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_ENABLE_CTR_MODE
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
#define LTC_CBC_MODE
|
||||
#endif
|
||||
|
||||
@@ -35,6 +35,14 @@
|
||||
#define LTC_CTR_MODE
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_ENABLE_GCM_MODE
|
||||
#define LTC_GCM_MODE
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_CHACHA20POLY1305
|
||||
#define LTC_CHACHA
|
||||
#define LTC_POLY1305
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_SHA512
|
||||
#define LTC_SHA512
|
||||
|
||||
@@ -667,16 +667,16 @@ int der_printable_value_decode(int v);
|
||||
|
||||
/* UTF-8 */
|
||||
#if (defined(SIZE_MAX) || __STDC_VERSION__ >= 199901L || defined(WCHAR_MAX) || defined(__WCHAR_MAX__) || defined(_WCHAR_T) || defined(_WCHAR_T_DEFINED) || defined (__WCHAR_TYPE__)) && !defined(LTC_NO_WCHAR)
|
||||
#include <wchar.h>
|
||||
#if defined(__WCHAR_MAX__)
|
||||
#define LTC_WCHAR_MAX __WCHAR_MAX__
|
||||
#elif defined(WCHAR_MAX)
|
||||
#define LTC_WCHAR_MAX WCHAR_MAX
|
||||
#endif
|
||||
#if defined(__WCHAR_MAX__)
|
||||
#define LTC_WCHAR_MAX __WCHAR_MAX__
|
||||
#else
|
||||
#include <wchar.h>
|
||||
#define LTC_WCHAR_MAX WCHAR_MAX
|
||||
#endif
|
||||
/* please note that it might happen that LTC_WCHAR_MAX is undefined */
|
||||
#else
|
||||
typedef ulong32 wchar_t;
|
||||
#define LTC_WCHAR_MAX 0xFFFFFFFF
|
||||
typedef ulong32 wchar_t;
|
||||
#define LTC_WCHAR_MAX 0xFFFFFFFF
|
||||
#endif
|
||||
|
||||
int der_encode_utf8_string(const wchar_t *in, unsigned long inlen,
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
int blake2bmac_file(const char *fname, const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen)
|
||||
{
|
||||
#ifdef LTC_NO_FILE
|
||||
LTC_UNUSED_PARAM(fname);
|
||||
LTC_UNUSED_PARAM(key);
|
||||
LTC_UNUSED_PARAM(keylen);
|
||||
LTC_UNUSED_PARAM(mac);
|
||||
LTC_UNUSED_PARAM(maclen);
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
blake2bmac_state st;
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
int blake2smac_file(const char *fname, const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen)
|
||||
{
|
||||
#ifdef LTC_NO_FILE
|
||||
LTC_UNUSED_PARAM(fname);
|
||||
LTC_UNUSED_PARAM(key);
|
||||
LTC_UNUSED_PARAM(keylen);
|
||||
LTC_UNUSED_PARAM(mac);
|
||||
LTC_UNUSED_PARAM(maclen);
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
blake2smac_state st;
|
||||
|
||||
@@ -31,6 +31,12 @@ int f9_file(int cipher,
|
||||
unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
#ifdef LTC_NO_FILE
|
||||
LTC_UNUSED_PARAM(cipher);
|
||||
LTC_UNUSED_PARAM(key);
|
||||
LTC_UNUSED_PARAM(keylen);
|
||||
LTC_UNUSED_PARAM(fname);
|
||||
LTC_UNUSED_PARAM(out);
|
||||
LTC_UNUSED_PARAM(outlen);
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
size_t x;
|
||||
|
||||
@@ -30,7 +30,12 @@ int hmac_file(int hash, const char *fname,
|
||||
unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
#ifdef LTC_NO_FILE
|
||||
(void)hash; (void)fname; (void)key; (void)keylen; (void)out; (void)outlen;
|
||||
LTC_UNUSED_PARAM(hash);
|
||||
LTC_UNUSED_PARAM(fname);
|
||||
LTC_UNUSED_PARAM(key);
|
||||
LTC_UNUSED_PARAM(keylen);
|
||||
LTC_UNUSED_PARAM(out);
|
||||
LTC_UNUSED_PARAM(outlen);
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
hmac_state hmac;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
Initialize an HMAC context.
|
||||
@param hmac The HMAC state
|
||||
@param hash The index of the hash you want to use
|
||||
@param hash The index of the hash you want to use
|
||||
@param key The secret key
|
||||
@param keylen The length of the secret key (octets)
|
||||
@return CRYPT_OK if successful
|
||||
@@ -64,9 +64,9 @@ int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned lon
|
||||
XMEMCPY(hmac->key, key, (size_t)keylen);
|
||||
}
|
||||
|
||||
if(keylen < LTC_HMAC_BLOCKSIZE) {
|
||||
zeromem((hmac->key) + keylen, (size_t)(LTC_HMAC_BLOCKSIZE - keylen));
|
||||
}
|
||||
if(keylen < LTC_HMAC_BLOCKSIZE) {
|
||||
zeromem((hmac->key) + keylen, (size_t)(LTC_HMAC_BLOCKSIZE - keylen));
|
||||
}
|
||||
|
||||
/* Create the initialization vector for step (3) */
|
||||
for(i=0; i < LTC_HMAC_BLOCKSIZE; i++) {
|
||||
@@ -89,8 +89,8 @@ done:
|
||||
#ifdef LTC_CLEAN_STACK
|
||||
zeromem(buf, LTC_HMAC_BLOCKSIZE);
|
||||
#endif
|
||||
|
||||
return err;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,6 +31,12 @@ int omac_file(int cipher,
|
||||
unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
#ifdef LTC_NO_FILE
|
||||
LTC_UNUSED_PARAM(cipher);
|
||||
LTC_UNUSED_PARAM(key);
|
||||
LTC_UNUSED_PARAM(keylen);
|
||||
LTC_UNUSED_PARAM(filename);
|
||||
LTC_UNUSED_PARAM(out);
|
||||
LTC_UNUSED_PARAM(outlen);
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
size_t x;
|
||||
|
||||
@@ -31,6 +31,12 @@ int pmac_file(int cipher,
|
||||
unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
#ifdef LTC_NO_FILE
|
||||
LTC_UNUSED_PARAM(cipher);
|
||||
LTC_UNUSED_PARAM(key);
|
||||
LTC_UNUSED_PARAM(keylen);
|
||||
LTC_UNUSED_PARAM(filename);
|
||||
LTC_UNUSED_PARAM(out);
|
||||
LTC_UNUSED_PARAM(outlen);
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
size_t x;
|
||||
|
||||
@@ -28,6 +28,11 @@
|
||||
int poly1305_file(const char *fname, const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen)
|
||||
{
|
||||
#ifdef LTC_NO_FILE
|
||||
LTC_UNUSED_PARAM(fname);
|
||||
LTC_UNUSED_PARAM(key);
|
||||
LTC_UNUSED_PARAM(keylen);
|
||||
LTC_UNUSED_PARAM(mac);
|
||||
LTC_UNUSED_PARAM(maclen);
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
poly1305_state st;
|
||||
|
||||
@@ -31,6 +31,12 @@ int xcbc_file(int cipher,
|
||||
unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
#ifdef LTC_NO_FILE
|
||||
LTC_UNUSED_PARAM(cipher);
|
||||
LTC_UNUSED_PARAM(key);
|
||||
LTC_UNUSED_PARAM(keylen);
|
||||
LTC_UNUSED_PARAM(filename);
|
||||
LTC_UNUSED_PARAM(out);
|
||||
LTC_UNUSED_PARAM(outlen);
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
size_t x;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user