├── .gitignore ├── LICENSE ├── Makefile.am ├── README.markdown ├── autogen.sh ├── configure.ac ├── debian ├── .gitignore ├── changelog ├── compat ├── control ├── copyright ├── passphrase-identity.manpages ├── rules ├── source │ └── format └── watch ├── m4 └── ax_check_compiler_flags.m4 ├── man └── passphrase-identity.1 └── src ├── Makefile.am ├── buffer.c ├── buffer.h ├── buffer_writer.c ├── buffer_writer.h ├── main.c ├── memory.c ├── memory.h ├── openpgp.c ├── openpgp.h ├── openssh.c ├── openssh.h ├── profile.c ├── profile.h ├── readpassphrase.c ├── readpassphrase.h ├── sha-private.h ├── sha.h └── sha1.c /.gitignore: -------------------------------------------------------------------------------- 1 | passphrase-identity_*.orig.tar.gz 2 | debian/debhelper-build-stamp 3 | debian/autoreconf.* 4 | id_ed25519 5 | id_ed25519.pub 6 | *.a 7 | *.cma 8 | *.cmi 9 | *.cmo 10 | *.cmt 11 | *.cmti 12 | *.cmx 13 | *.cmxa 14 | *.la 15 | *.lai 16 | *.lo 17 | *.log 18 | *.o 19 | *.so 20 | *.swp 21 | *.test 22 | *.trs 23 | *_TEST 24 | *~ 25 | .deps 26 | .libs 27 | COPYING 28 | INSTALL 29 | Makefile 30 | Makefile.in 31 | aclocal.m4 32 | autom4te.cache 33 | compile 34 | config.guess 35 | config.h 36 | config.h.in 37 | config.log 38 | config.status 39 | config.sub 40 | configure 41 | depcomp 42 | install-sh 43 | libtool 44 | ltmain.sh 45 | m4/libtool.m4 46 | m4/ltoptions.m4 47 | m4/ltsugar.m4 48 | m4/ltversion.m4 49 | m4/lt~obsolete.m4 50 | missing 51 | src/config.h 52 | stamp-h1 53 | passphrase-identity 54 | test-driver 55 | tests/*.tmp.buffer 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Alexander Færøy. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | SUBDIRS = src 4 | 5 | dist_man_MANS = \ 6 | man/passphrase-identity.1 7 | 8 | EXTRA_DIST = LICENSE README.markdown 9 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Passphrase Identity 2 | 3 | Regenerable ed25519 keys for OpenSSH and OpenPGP. 4 | 5 | Passphrase Identity allows you to deterministically generate ed25519 key pairs (signing keys) for OpenSSH and OpenPGP from a set of parameters. 6 | This allows you to (re)generate your key pair on a computer which, for example, lacks persistent storage - it derives an "identity" from a passphrase. 7 | 8 | You must be able to remember three things to (re)generate your key pair; 9 | 10 | 1. A user defined "username", which can be any string. 11 | 2. A Passphrase-identity defined "profile" name. There's currently only two profiles available: `2015v1`, and `2017`, both of which use `scrypt()` + `salsa20/8` + `sha256` as KDF. 12 | 3. Your personally selected passphrase. 13 | 14 | ## Usage 15 | 16 | Usage: ./passphrase-identity [ options ] [ output directory ] 17 | 18 | Help Options: 19 | -h, --help Display this message (default behavior) 20 | 21 | Key Options: 22 | -u, --user Specify which username to use [as salt] 23 | -p, --profile Specify which profile to use 24 | 25 | Available Profiles: 26 | 27 | 2015v1 28 | 2017 29 | 30 | Output Format Options: 31 | 32 | -s, --openssh Output OpenSSH public and private key 33 | The keys are written to id_ed25519{,.pub} 34 | 35 | -g, --gpg Output OpenPGP public and private key 36 | The keys are written to {public,private}.asc 37 | 38 | ## Example Usage 39 | 40 | 1. We start by creating a key pair for OpenSSH using `ahf@passphrase-identity.0x90.dk` as username. 41 | 42 | $ ./passphrase-identity --openssh --user ahf@passphrase-identity.0x90.dk 43 | Passphrase: foobar 44 | Generating key pair using the '2015v1' profile ... 45 | This may take a little while ... 46 | Successfully generated key pair ... 47 | Saving OpenSSH secret key to id_ed25519 ... 48 | Saving OpenSSH public key to id_ed25519.pub ... 49 | 50 | $ cat id_ed25519 51 | -----BEGIN OPENSSH PRIVATE KEY----- 52 | b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW 53 | QyNTUxOQAAACArYR91DYHLCeYb+Ls3wyYsSJrADs7topOSlioZ6GNX2AAAAJj36teu9+rX 54 | rgAAAAtzc2gtZWQyNTUxOQAAACArYR91DYHLCeYb+Ls3wyYsSJrADs7topOSlioZ6GNX2A 55 | AAAEAv/A/ak2U1vqbQR7sDFmJFp1eC7kv0HdZYm4Dt50n33ythH3UNgcsJ5hv4uzfDJixI 56 | msAOzu2ik5KWKhnoY1fYAAAAEWFoZkB0ZW5lby4weDkwLmRrAQIDBA== 57 | -----END OPENSSH PRIVATE KEY----- 58 | 59 | $ cat id_ed25519.pub 60 | ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICthH3UNgcsJ5hv4uzfDJixImsAOzu2ik5KWKhnoY1fY ahf@passphrase-identity.0x90.dk 61 | 62 | $ openssl sha256 id_ed25519.pub 63 | SHA256(id_ed25519.pub)= a394eb08102eefb020d3274285671d113604690bedb551c5dfbf27c0d6844482 64 | 65 | 2. Wipe the key pair. 66 | 67 | $ shred -u id_ed25519 68 | $ shred -u id_ed25519.pub 69 | 70 | 3. Create the key again using the same parameters and passphrase. 71 | 72 | $ ./passphrase-identity --openssh --user ahf@passphrase-identity.0x90.dk 73 | Passphrase: foobar 74 | Generating key pair using the '2015v1' profile ... 75 | This may take a little while ... 76 | Successfully generated key pair ... 77 | Saving OpenSSH secret key to id_ed25519 ... 78 | Saving OpenSSH public key to id_ed25519.pub ... 79 | 80 | $ openssl sha256 id_ed25519.pub 81 | SHA256(id_ed25519.pub)= a394eb08102eefb020d3274285671d113604690bedb551c5dfbf27c0d6844482 82 | 83 | ## Compiling on Ubuntu 84 | 85 | ```bash 86 | # if you want to use a proxy for git via https: 87 | # git config --global http.proxy 'socks5://127.0.0.1:9150' 88 | 89 | git clone https://github.com/ahf/passphrase-identity 90 | apt-get install autoconf libtool pkg-config libsodium-dev -y 91 | cd passphrase-identity/ 92 | ./autogen.sh 93 | ./configure 94 | make 95 | # Binary will be named ./src/passphrase-identity 96 | ``` 97 | 98 | ## Authors 99 | 100 | - [Alexander Færøy](https://twitter.com/ahfaeroey) ([ahf@0x90.dk](mailto:ahf@0x90.dk)). 101 | 102 | ## Todo 103 | 104 | 1. Code clean-up. This is a prototype written during two evenings of a weekend. 105 | 2. Consider the new Tor ed25519 ID keys? 106 | 3. Add proper tests. Use Travis CI to build on both OS X and Linux. 107 | 4. Add fancy graphics after key generation, like the OpenSSH client, such that 108 | the user can quickly identify if something is wrong. 109 | 5. Add cracklib support and remember to make it possible to disable it as well. 110 | 111 | ## License 112 | 113 | See the LICENSE file. 114 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | autoreconf --install --force 4 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.69]) 2 | AC_INIT([passphrase-identity],[1.0.0],[ahf@0x90.dk],[passphrase-identity],[]) 3 | 4 | AC_CONFIG_SRCDIR([src/main.c]) 5 | AC_CONFIG_HEADERS([config.h]) 6 | 7 | AM_INIT_AUTOMAKE([foreign]) 8 | AM_SILENT_RULES([yes]) 9 | AC_CONFIG_MACRO_DIR([m4]) 10 | 11 | AC_LANG([C]) 12 | 13 | AC_PROG_CC 14 | AC_PROG_CC_STDC 15 | AC_PROG_INSTALL 16 | LT_INIT 17 | LT_PATH_LD 18 | 19 | PKG_CHECK_MODULES([SODIUM], [libsodium]) 20 | 21 | GLIB_TESTS 22 | 23 | PASSPHRASE_IDENTITY_CFLAGS= 24 | 25 | PREFERRED_CFLAGS="-pedantic -Werror -Wall -Wextra -Wbad-function-cast -Wcast-align -Wcast-qual -Wfloat-equal -Wformat=2 -Wformat-security -Wformat-nonliteral -Winit-self -Winline -Wmissing-prototypes -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wpointer-arith -Wredundant-decls -Wshadow -Wswitch-default -Wunused -Wunused-result -fPIE" 26 | LDFLAGS="$LDFLAGS -pie -z relro -z now" 27 | 28 | for flag in $PREFERRED_CFLAGS; do 29 | AX_CHECK_COMPILER_FLAGS([$flag], [PASSPHRASE_IDENTITY_CFLAGS="$PASSPHRASE_IDENTITY_CFLAGS $flag"],) 30 | done 31 | 32 | AC_SUBST([PASSPHRASE_IDENTITY_CFLAGS]) 33 | 34 | AC_CONFIG_FILES([ 35 | Makefile 36 | src/Makefile 37 | ]) 38 | 39 | AC_OUTPUT 40 | -------------------------------------------------------------------------------- /debian/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.substvars 3 | *.debhelper 4 | autoreconf.* 5 | /files 6 | /passphrase-identity 7 | /passphrase-identity-dev 8 | /tmp 9 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | passphrase-identity (1.0.0-1) unstable; urgency=medium 2 | 3 | * Initial release. 4 | 5 | -- Alexander Færøy Mon, 24 Apr 2017 16:07:37 +0000 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: passphrase-identity 2 | Section: net 3 | Priority: optional 4 | Maintainer: Alexander Færøy 5 | Standards-Version: 3.9.7 6 | Build-Depends: libtool (>= 2.4.6), 7 | pkg-config (>= 0.29), 8 | libsodium-dev (>= 1.0.8-5), 9 | autoconf (>= 2.69), 10 | debhelper (>= 9.20160115), 11 | dh-autoreconf (>= 11), 12 | dh-strip-nondeterminism (>= 0.015) 13 | 14 | Package: passphrase-identity 15 | Architecture: any 16 | Depends: ${shlibs:Depends}, ${misc:Depends} 17 | Description: Regenerable ed25519 keys for OpenSSH and OpenPGP 18 | Passphrase-identity allows you to deterministically generate 19 | ed25519 key pairs (signing keys) for OpenSSH and OpenPGP from a passphrase. 20 | This allows you to (re)generate your key pair on a computer which, for example, 21 | lacks persistent storage. 22 | The passphrase is salted with a username and a pre-set scrypt profile. 23 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: passphrase-identity 3 | Upstream-Contact: Alexander Færøy 4 | Source: https://github.com/ahf/passphrase-identity 5 | 6 | Files: * 7 | Copyright: 2015-2017 Alexander Færøy 8 | License: MPL-1.1 or GPL-2 or LGPL-2.1 or BSD-3-clause 9 | 10 | Files: src/readpassphrase.* 11 | Copyright: 2000-2002, 2007 Todd C. Miller 12 | License: TODD-DARPA 13 | 14 | Files: src/sha1.c src/sha.h src/sha-private.h 15 | Copyright: 2011 IETF Trust and the persons identified as authors of the code. All rights reserved. 16 | License: See src/sha.h for terms of use and redistribution. 17 | 18 | Files: m4/* 19 | Copyright: 1992-2009 Free Software Foundation 20 | License: GPL-2 21 | 22 | Files: debian/* 23 | Copyright: 2015 Ximin Luo 24 | License: MPL-1.1 or GPL-2 or LGPL-2.1 25 | 26 | License: MPL-1.1 27 | The complete text of the Mozilla Public License can be found in 28 | the `LICENSE' file in the top-level directory of this package. 29 | 30 | License: GPL-2 31 | On Debian systems, the complete text of the GNU General Public 32 | License can be found in the file /usr/share/common-licenses/GPL-2'. 33 | 34 | License: LGPL-2.1 35 | On Debian systems, the complete text of the GNU Lesser General Public 36 | License can be found in the file `/usr/share/common-licenses/LGPL-2.1'. 37 | 38 | License: TODD-DARPA 39 | Permission to use, copy, modify, and distribute this software for any 40 | purpose with or without fee is hereby granted, provided that the above 41 | copyright notice and this permission notice appear in all copies. 42 | . 43 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 44 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 45 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 46 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 47 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 48 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 49 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 50 | . 51 | Sponsored in part by the Defense Advanced Research Projects 52 | Agency (DARPA) and Air Force Research Laboratory, Air Force 53 | Materiel Command, USAF, under agreement number F39502-99-1-0512. 54 | 55 | License: BSD-3-clause 56 | Copyright (c) 2017, Alexander Færøy 57 | All rights reserved. 58 | . 59 | Redistribution and use in source and binary forms, with or without 60 | modification, are permitted provided that the following conditions are met: 61 | * Redistributions of source code must retain the above copyright 62 | notice, this list of conditions and the following disclaimer. 63 | * Redistributions in binary form must reproduce the above copyright 64 | notice, this list of conditions and the following disclaimer in the 65 | documentation and/or other materials provided with the distribution. 66 | * Neither the name of the nor the 67 | names of its contributors may be used to endorse or promote products 68 | derived from this software without specific prior written permission. 69 | . 70 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 71 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 72 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 73 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 74 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 75 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 76 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 77 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 78 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 79 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 80 | -------------------------------------------------------------------------------- /debian/passphrase-identity.manpages: -------------------------------------------------------------------------------- 1 | man/passphrase-identity.1 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | # Uncomment this to turn on verbose mode. 4 | #export DH_VERBOSE=1 5 | 6 | build: 7 | dh "$@" --with-autoreconf 8 | 9 | %: 10 | dh $@ --with autoreconf 11 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | version=4 2 | opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%-$1.tar.gz%" \ 3 | https://github.com/ahf/passphrase-identity/tags \ 4 | (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate 5 | -------------------------------------------------------------------------------- /m4/ax_check_compiler_flags.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.nongnu.org/autoconf-archive/ax_check_compiler_flags.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_COMPILER_FLAGS(FLAGS, [ACTION-SUCCESS], [ACTION-FAILURE]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check whether the given compiler FLAGS work with the current language's 12 | # compiler, or whether they give an error. (Warnings, however, are 13 | # ignored.) 14 | # 15 | # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on 16 | # success/failure. 17 | # 18 | # LICENSE 19 | # 20 | # Copyright (c) 2009 Steven G. Johnson 21 | # Copyright (c) 2009 Matteo Frigo 22 | # 23 | # This program is free software: you can redistribute it and/or modify it 24 | # under the terms of the GNU General Public License as published by the 25 | # Free Software Foundation, either version 3 of the License, or (at your 26 | # option) any later version. 27 | # 28 | # This program is distributed in the hope that it will be useful, but 29 | # WITHOUT ANY WARRANTY; without even the implied warranty of 30 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 31 | # Public License for more details. 32 | # 33 | # You should have received a copy of the GNU General Public License along 34 | # with this program. If not, see . 35 | # 36 | # As a special exception, the respective Autoconf Macro's copyright owner 37 | # gives unlimited permission to copy, distribute and modify the configure 38 | # scripts that are the output of Autoconf when processing the Macro. You 39 | # need not follow the terms of the GNU General Public License when using 40 | # or distributing such scripts, even though portions of the text of the 41 | # Macro appear in them. The GNU General Public License (GPL) does govern 42 | # all other use of the material that constitutes the Autoconf Macro. 43 | # 44 | # This special exception to the GPL applies to versions of the Autoconf 45 | # Macro released by the Autoconf Archive. When you make and distribute a 46 | # modified version of the Autoconf Macro, you may extend this special 47 | # exception to the GPL to apply to your modified version as well. 48 | 49 | AC_DEFUN([AX_CHECK_COMPILER_FLAGS], 50 | [AC_PREREQ(2.59) dnl for _AC_LANG_PREFIX 51 | AC_MSG_CHECKING([whether _AC_LANG compiler accepts $1]) 52 | dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname: 53 | AS_LITERAL_IF([$1], 54 | [AC_CACHE_VAL(AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1]), [ 55 | ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS 56 | _AC_LANG_PREFIX[]FLAGS="$1" 57 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], 58 | AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=yes, 59 | AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=no) 60 | _AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])], 61 | [ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS 62 | _AC_LANG_PREFIX[]FLAGS="$1" 63 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], 64 | eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=yes, 65 | eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=no) 66 | _AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS]) 67 | eval ax_check_compiler_flags=$AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1]) 68 | AC_MSG_RESULT($ax_check_compiler_flags) 69 | if test "x$ax_check_compiler_flags" = xyes; then 70 | m4_default([$2], :) 71 | else 72 | m4_default([$3], :) 73 | fi 74 | ])dnl AX_CHECK_COMPILER_FLAGS 75 | -------------------------------------------------------------------------------- /man/passphrase-identity.1: -------------------------------------------------------------------------------- 1 | .TH ID "1" "February 2016" "GNU coreutils 8.25" "User Commands" 2 | .SH NAME 3 | passphrase-identity \- Regenerable ed25519 keys for OpenSSH 4 | .SH SYNOPSIS 5 | .B passphrase-identity 6 | [\fI\,options\/\fR]... [\fI\,output directory\/\fR] 7 | .SH DESCRIPTION 8 | .\" Add any additional description here 9 | .PP 10 | Passphrase-identity allows you to deterministically generate an ed25519 key pair for OpenSSH 11 | from a set of parameters. This allows you to (re)generate your key pair on a 12 | computer which, for example, lacks persistent storage. 13 | 14 | You must be able to remember three things to (re)generate your key pair; 15 | 16 | 1. A user defined "username", which can be any string. 17 | 18 | 2. A Passphrase-identity defined "profile" name. See \fBAvailable Profiles\fR. 19 | 20 | 3. Your personally selected passphrase. 21 | .SS "Available Profiles:" 22 | .TP 23 | .IP 24 | \fB2015v1\fR - scrypt() + salsa20/8 + sha256 as KDF 25 | .TP 26 | .IP 27 | \fB2017\fR - scrypt() + salsa20/8 + sha256 as KDF 28 | .SS "Key Options:" 29 | .TP 30 | \fB\-u\fR, \fB\-\-user\fR 31 | Specify which username to use [as salt] 32 | .TP 33 | \fB\-p\fR, \fB\-\-profile\fR 34 | Specify which KDF profile to use 35 | .SS "Output Format Options:" 36 | .TP 37 | \fB\-s\fR, \fB\-\-openssh\fR 38 | Output OpenSSH public and private key \fBid_ed25519{,.pub}\fR 39 | .TP 40 | \fB\-g\fR, \fB\-\-gpg\fR 41 | Output OpenPGP public and private key \fBopenpgp.asc\fR 42 | .SS "Help Options:" 43 | .TP 44 | \fB\-\-help\fR 45 | display option help information and exit 46 | .PP 47 | Without any OPTION, print \fB--help\fR and exit. 48 | .SH AUTHOR 49 | Written by Alexander Færøy . 50 | .SH "REPORTING BUGS" 51 | Github issue page: 52 | .SH COPYRIGHT 53 | Copyright \(co 2017 Alexander Færøy 54 | .TP 55 | License: BSD-3-clause 56 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = passphrase-identity 2 | 3 | passphrase_identity_CFLAGS = @PASSPHRASE_IDENTITY_CFLAGS@ @SODIUM_CFLAGS@ 4 | passphrase_identity_LDFLAGS = @SODIUM_LIBS@ 5 | 6 | passphrase_identity_SOURCES = \ 7 | main.c \ 8 | buffer.c buffer.h \ 9 | buffer_writer.c buffer_writer.h \ 10 | memory.c memory.h \ 11 | openssh.c openssh.h \ 12 | sha1.c sha.h sha-private.h \ 13 | openpgp.c openpgp.h \ 14 | profile.c profile.h \ 15 | readpassphrase.c readpassphrase.h 16 | -------------------------------------------------------------------------------- /src/buffer.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include "buffer.h" 10 | #include "memory.h" 11 | 12 | static unsigned char base64_encoding_table[] = { 13 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 14 | 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 15 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 16 | 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 17 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 18 | 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 19 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', 20 | '4', '5', '6', '7', '8', '9', '+', '/' 21 | }; 22 | 23 | static unsigned char base64_decoding_table[256]; 24 | 25 | static int base64_mod_table[] = { 0, 2, 1 }; 26 | 27 | void __attribute__((constructor)) buffer_init(void) 28 | { 29 | for (int i = 0; i < 64; ++i) 30 | { 31 | base64_decoding_table[base64_encoding_table[i]] = i; 32 | } 33 | } 34 | 35 | struct buffer* MUSTCHECK buffer_new(size_t size) 36 | { 37 | struct buffer *buffer = NULL; 38 | 39 | buffer = malloc(sizeof(*buffer)); 40 | if (NULL == buffer) 41 | return NULL; 42 | 43 | buffer->size = size; 44 | // We allocate an extra byte, which is always set to zero. 45 | buffer->data = secure_malloc(size + 1); 46 | 47 | if (NULL == buffer->data) 48 | { 49 | memory_zero(buffer, sizeof(buffer)); 50 | free(buffer); 51 | buffer = NULL; 52 | } 53 | 54 | return buffer; 55 | } 56 | 57 | struct buffer* MUSTCHECK buffer_new_from_string(char *string) 58 | { 59 | if (string == NULL) 60 | return NULL; 61 | 62 | return buffer_new_from_raw_buffer((unsigned char *)string, strlen(string)); 63 | } 64 | 65 | struct buffer* MUSTCHECK buffer_new_random(size_t size) 66 | { 67 | struct buffer *buffer = NULL; 68 | 69 | buffer = buffer_new(size); 70 | if (NULL != buffer) 71 | randombytes_buf(buffer->data, size); 72 | 73 | return buffer; 74 | } 75 | 76 | struct buffer* MUSTCHECK buffer_new_from_raw_buffer(unsigned char *data, size_t size) 77 | { 78 | struct buffer *buffer = NULL; 79 | 80 | if(NULL == data) 81 | return NULL; 82 | 83 | buffer = buffer_new(size); 84 | if (NULL != buffer) 85 | memcpy(buffer->data, data, size); 86 | 87 | return buffer; 88 | } 89 | 90 | void buffer_free(struct buffer *buffer) 91 | { 92 | if (buffer == NULL) 93 | return; 94 | 95 | if (buffer->data != NULL) 96 | { 97 | // shred the data: 98 | secure_free(buffer->data); 99 | buffer->data = NULL; 100 | } 101 | 102 | // get rid of ->data pointer + ->size: 103 | sodium_memzero(buffer, sizeof(struct buffer)); 104 | free(buffer); 105 | } 106 | 107 | char *buffer_string(const struct buffer *buffer) 108 | { 109 | if (buffer == NULL) 110 | return NULL; 111 | 112 | return (char *)buffer->data; 113 | } 114 | 115 | size_t buffer_size(const struct buffer *buffer) 116 | { 117 | if (buffer == NULL) 118 | return 0; 119 | 120 | return buffer->size; 121 | } 122 | 123 | bool MUSTCHECK buffer_equal(const struct buffer *buffer, const struct buffer *other_buffer) 124 | { 125 | if (buffer == NULL || other_buffer == NULL) 126 | return false; 127 | 128 | if (buffer->size != other_buffer->size) 129 | return false; 130 | 131 | if (NULL == buffer->data || NULL == other_buffer->data) 132 | return false; 133 | 134 | return memory_equal(buffer->data, other_buffer->data, buffer->size); 135 | } 136 | 137 | bool MUSTCHECK buffer_hex_encode(const struct buffer *buffer, struct buffer **result) 138 | { 139 | struct buffer *value = NULL; 140 | 141 | if (buffer == NULL || result == NULL) 142 | return false; 143 | 144 | value = buffer_new(buffer->size * 2); 145 | if (NULL == value) 146 | return false; 147 | 148 | sodium_bin2hex((char *)value->data, value->size, buffer->data, buffer->size); 149 | 150 | *result = value; 151 | 152 | return true; 153 | } 154 | 155 | bool MUSTCHECK buffer_hex_decode(const struct buffer *buffer, struct buffer **result) 156 | { 157 | struct buffer *value = NULL; 158 | 159 | if (buffer == NULL || result == NULL) 160 | return false; 161 | 162 | value = buffer_new(buffer->size / 2); 163 | if (NULL == value) 164 | return false; 165 | 166 | sodium_hex2bin(value->data, value->size, (char *)buffer->data, buffer->size, ": ", NULL, NULL); 167 | *result = value; 168 | 169 | return true; 170 | } 171 | 172 | bool MUSTCHECK buffer_base64_encoded_size(const struct buffer *buffer, size_t *projected_size) 173 | { 174 | if(NULL == buffer || NULL == projected_size) 175 | return false; 176 | 177 | // check for overflow, rounding down: 178 | if(buffer->size > ((SIZE_MAX-3) / 4) * 3) 179 | return false; 180 | 181 | // see implementation in buffer_base64_encode below 182 | *projected_size = 4 * ((buffer->size + 2)/3); 183 | return true; 184 | } 185 | 186 | bool MUSTCHECK buffer_base64_encode(const struct buffer *buffer, struct buffer **result) 187 | { 188 | struct buffer *value = NULL; 189 | 190 | if (buffer == NULL || result == NULL) 191 | return false; 192 | 193 | size_t encoded_size = 0; 194 | if(!buffer_base64_encoded_size(buffer, &encoded_size)) 195 | return false; 196 | 197 | value = buffer_new(encoded_size); 198 | if (NULL == value) 199 | return false; 200 | 201 | for (size_t i = 0, j = 0; i < buffer->size; ) 202 | { 203 | uint32_t a = i < buffer->size ? buffer->data[i++] : 0; 204 | uint32_t b = i < buffer->size ? buffer->data[i++] : 0; 205 | uint32_t c = i < buffer->size ? buffer->data[i++] : 0; 206 | uint32_t triplet = (a << 0x10) + (b << 0x08) + c; 207 | 208 | value->data[j++] = base64_encoding_table[(triplet >> 3 * 6) & 0x3F]; 209 | value->data[j++] = base64_encoding_table[(triplet >> 2 * 6) & 0x3F]; 210 | value->data[j++] = base64_encoding_table[(triplet >> 1 * 6) & 0x3F]; 211 | value->data[j++] = base64_encoding_table[(triplet >> 0 * 6) & 0x3F]; 212 | } 213 | 214 | for (int i = 0; i < base64_mod_table[buffer->size % 3]; i++) 215 | value->data[value->size - 1 - i] = '='; 216 | 217 | *result = value; 218 | 219 | return true; 220 | } 221 | 222 | bool MUSTCHECK buffer_base64_decoded_size(const struct buffer *buffer, size_t *projected_size) 223 | { 224 | if(NULL == buffer || NULL == projected_size) 225 | return false; 226 | 227 | if (buffer->size % 4 != 0) return false; 228 | // { 229 | // if(buffer->size % 4 == 1 && '\0' != *(buffer->data + buffer->size -1)) 230 | // return false; 231 | // } 232 | 233 | *projected_size = (buffer->size / 4) * 3; 234 | 235 | return true; 236 | } 237 | 238 | bool MUSTCHECK buffer_base64_decode(const struct buffer *buffer, struct buffer **result) 239 | { 240 | struct buffer *value = NULL; 241 | size_t value_size = 0; 242 | 243 | if (NULL == result) 244 | return false; 245 | 246 | // make sure decoding table is initiated: 247 | if('3' != base64_decoding_table[base64_encoding_table['3']]) 248 | buffer_init(); 249 | 250 | if(!buffer_base64_decoded_size(buffer, &value_size)) 251 | return false; 252 | 253 | if (buffer->data[buffer->size - 1] == '=') 254 | --value_size; 255 | 256 | if (buffer->data[buffer->size - 2] == '=') 257 | --value_size; 258 | 259 | value = buffer_new(value_size); 260 | if (NULL == value) 261 | return false; 262 | 263 | for (size_t i = 0, j = 0; i < buffer->size; ) 264 | { 265 | uint32_t a = buffer->data[i] == '=' ? 0 & i++ : base64_decoding_table[buffer->data[i++]]; 266 | uint32_t b = buffer->data[i] == '=' ? 0 & i++ : base64_decoding_table[buffer->data[i++]]; 267 | uint32_t c = buffer->data[i] == '=' ? 0 & i++ : base64_decoding_table[buffer->data[i++]]; 268 | uint32_t d = buffer->data[i] == '=' ? 0 & i++ : base64_decoding_table[buffer->data[i++]]; 269 | 270 | uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6); 271 | 272 | if (j < value->size) 273 | value->data[j++] = (triple >> 2 * 8) & 0xFF; 274 | 275 | if (j < value->size) 276 | value->data[j++] = (triple >> 1 * 8) & 0xFF; 277 | 278 | if (j < value->size) 279 | value->data[j++] = (triple >> 0 * 8) & 0xFF; 280 | } 281 | 282 | *result = value; 283 | 284 | return true; 285 | } 286 | -------------------------------------------------------------------------------- /src/buffer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #ifndef GUARD_BUFFER_H 6 | #define GUARD_BUFFER_H 1 7 | 8 | #include 9 | #include 10 | 11 | // this attribute is supported by clang and gcc: 12 | #define MUSTCHECK __attribute__((warn_unused_result)) 13 | 14 | struct buffer 15 | { 16 | size_t size; 17 | unsigned char *data; 18 | }; 19 | 20 | void buffer_init(void); 21 | 22 | struct buffer* MUSTCHECK buffer_new(size_t size); 23 | struct buffer* MUSTCHECK buffer_new_from_string(char *string); 24 | struct buffer* MUSTCHECK buffer_new_from_raw_buffer(unsigned char *data, size_t size); 25 | struct buffer* MUSTCHECK buffer_new_random(size_t size); 26 | 27 | void buffer_free(struct buffer *buffer); 28 | 29 | char *buffer_string(const struct buffer *buffer); 30 | size_t buffer_size(const struct buffer *buffer); 31 | 32 | bool MUSTCHECK buffer_equal(const struct buffer *buffer, const struct buffer *other_buffer); 33 | 34 | bool MUSTCHECK buffer_hex_encode(const struct buffer *buffer, struct buffer **result); 35 | bool MUSTCHECK buffer_hex_decode(const struct buffer *buffer, struct buffer **result); 36 | 37 | bool MUSTCHECK buffer_base64_encoded_size(const struct buffer *buffer, size_t *projected_size); 38 | bool MUSTCHECK buffer_base64_encode(const struct buffer *buffer, struct buffer **result); 39 | 40 | bool MUSTCHECK buffer_base64_decoded_size(const struct buffer *buffer, size_t *projected_size); 41 | bool MUSTCHECK buffer_base64_decode(const struct buffer *buffer, struct buffer **result); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/buffer_writer.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "buffer_writer.h" 10 | #include "memory.h" 11 | 12 | buffer_writer_t* buffer_writer_new(struct buffer *buffer) 13 | { 14 | if (buffer == NULL) 15 | return NULL; 16 | 17 | buffer_writer_t *buffer_writer = NULL; 18 | 19 | buffer_writer = malloc(sizeof(*buffer_writer)); 20 | assert(buffer_writer != NULL); 21 | 22 | buffer_writer->write_offset = 0; 23 | buffer_writer->buffer = buffer; 24 | 25 | return buffer_writer; 26 | } 27 | 28 | void buffer_writer_free(buffer_writer_t *buffer_writer) 29 | { 30 | free(buffer_writer); 31 | } 32 | 33 | void buffer_writer_reset(buffer_writer_t *buffer_writer) 34 | { 35 | buffer_writer_set_offset(buffer_writer, 0); 36 | } 37 | 38 | void buffer_writer_set_offset(buffer_writer_t *buffer_writer, size_t offset) 39 | { 40 | if (buffer_writer == NULL) 41 | return; 42 | 43 | buffer_writer->write_offset = offset; 44 | } 45 | 46 | bool MUSTCHECK buffer_writer_write_value(buffer_writer_t *buffer_writer, const void *value, const size_t size) 47 | { 48 | if (buffer_writer == NULL || buffer_writer->buffer == NULL 49 | || value == NULL 50 | || NULL == buffer_writer->buffer->data) 51 | return false; 52 | 53 | if (buffer_writer->write_offset + size > buffer_writer->buffer->size) 54 | return false; 55 | 56 | memcpy(buffer_writer->buffer->data + buffer_writer->write_offset, value, size); 57 | buffer_writer->write_offset += size; 58 | 59 | return true; 60 | } 61 | 62 | bool MUSTCHECK buffer_writer_write_buffer(buffer_writer_t *buffer_writer, const buffer_writer_t *srcbuf) 63 | { 64 | if(NULL == srcbuf || NULL == srcbuf->buffer) 65 | return false; 66 | return buffer_writer_write_value(buffer_writer, srcbuf->buffer->data, srcbuf->write_offset); 67 | } 68 | 69 | bool MUSTCHECK buffer_writer_write_asciiz_with_linewrapping(buffer_writer_t *buffer_writer, const char *str, const size_t linewrapping) 70 | { 71 | if(NULL == buffer_writer || NULL == buffer_writer->buffer 72 | || NULL == buffer_writer->buffer->data 73 | || NULL == str) 74 | return false; 75 | 76 | size_t max_including_zero = 1 + buffer_writer->buffer->size - buffer_writer->write_offset; 77 | size_t s_len = strnlen(str, max_including_zero); 78 | 79 | if(s_len == max_including_zero) // longer than available 80 | return false; 81 | 82 | size_t required_linebreaks = linewrapping ? (s_len / linewrapping) : 0; 83 | 84 | size_t offset = 0; 85 | 86 | while(required_linebreaks != 0){ 87 | if( !buffer_writer_write_value(buffer_writer, str + offset, linewrapping) 88 | || !buffer_writer_write_value(buffer_writer, "\n", 1)) 89 | { 90 | // erase new half-added content, rewind the writer to original state 91 | size_t windback_offset = max_including_zero - 1 - buffer_writer->buffer->size; 92 | memory_zero(buffer_writer->buffer->data + windback_offset, buffer_writer->write_offset - windback_offset); 93 | buffer_writer_set_offset(buffer_writer, windback_offset); 94 | return false; 95 | } 96 | offset = offset + linewrapping; 97 | required_linebreaks -= 1; 98 | } 99 | 100 | return buffer_writer_write_value(buffer_writer, str + offset, s_len - offset); 101 | } 102 | 103 | bool MUSTCHECK buffer_writer_write_asciiz(buffer_writer_t *buffer_writer, const char *str) 104 | { 105 | return buffer_writer_write_asciiz_with_linewrapping(buffer_writer, str, 0); 106 | } 107 | 108 | bool MUSTCHECK buffer_writer_write_uint8(buffer_writer_t *buffer_writer, uint8_t value) 109 | { 110 | return buffer_writer_write_value(buffer_writer, &value, sizeof(value)); 111 | } 112 | 113 | bool MUSTCHECK buffer_writer_write_uint16(buffer_writer_t *buffer_writer, uint16_t value) 114 | { 115 | uint16_t v = htons(value); 116 | 117 | return buffer_writer_write_value(buffer_writer, &v, sizeof(v)); 118 | } 119 | 120 | bool MUSTCHECK buffer_writer_write_uint32(buffer_writer_t *buffer_writer, uint32_t value) 121 | { 122 | uint32_t v = htonl(value); 123 | 124 | return buffer_writer_write_value(buffer_writer, &v, sizeof(v)); 125 | } 126 | -------------------------------------------------------------------------------- /src/buffer_writer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #ifndef GUARD_BUFFER_WRITER_H 6 | #define GUARD_BUFFER_WRITER_H 1 7 | 8 | #include 9 | 10 | #include "buffer.h" 11 | 12 | struct buffer_writer 13 | { 14 | size_t write_offset; 15 | struct buffer *buffer; 16 | }; 17 | 18 | typedef struct buffer_writer buffer_writer_t; 19 | 20 | buffer_writer_t* MUSTCHECK buffer_writer_new(struct buffer *buffer); 21 | 22 | void buffer_writer_free(buffer_writer_t *buffer_writer); 23 | 24 | void buffer_writer_reset(buffer_writer_t *buffer_writer); 25 | void buffer_writer_set_offset(buffer_writer_t *buffer_writer, size_t offset); 26 | 27 | bool MUSTCHECK buffer_writer_write_value(buffer_writer_t *buffer_writer, const void *value, size_t size); 28 | 29 | bool MUSTCHECK buffer_writer_write_buffer(buffer_writer_t *buffer_writer, const buffer_writer_t *srcbuf); 30 | 31 | bool MUSTCHECK buffer_writer_write_asciiz(buffer_writer_t *buffer_writer, const char *str); 32 | bool MUSTCHECK buffer_writer_write_asciiz_with_linewrapping(buffer_writer_t *buffer_writer, const char *str, const size_t linewrapping); 33 | 34 | bool MUSTCHECK buffer_writer_write_uint8(buffer_writer_t *buffer_writer, uint8_t value); 35 | bool MUSTCHECK buffer_writer_write_uint16(buffer_writer_t *buffer_writer, uint16_t value); 36 | bool MUSTCHECK buffer_writer_write_uint32(buffer_writer_t *buffer_writer, uint32_t value); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "buffer.h" 14 | #include "openssh.h" 15 | #include "openpgp.h" 16 | #include "profile.h" 17 | #include "readpassphrase.h" 18 | #include "memory.h" 19 | 20 | static void usage(const char *program) 21 | { 22 | fprintf(stderr, "Usage: %s [ options ] [ output directory ]\n", program); 23 | fprintf(stderr, "\n"); 24 | 25 | fprintf(stderr, "Help Options:\n"); 26 | fprintf(stderr, " -h, --help Display this message (default behavior)\n"); 27 | fprintf(stderr, "\n"); 28 | 29 | fprintf(stderr, "Key Options:\n"); 30 | fprintf(stderr, " -u, --user Specify which username to use [as salt]\n"); 31 | fprintf(stderr, " -p, --profile Specify which profile to use\n"); 32 | fprintf(stderr, "\n"); 33 | fprintf(stderr, " Available Profiles:\n"); 34 | fprintf(stderr, "\n"); 35 | fprintf(stderr, " 2015v1\n"); 36 | fprintf(stderr, " 2017\n"); 37 | fprintf(stderr, "\n"); 38 | 39 | fprintf(stderr, "Output Format Options:\n"); 40 | fprintf(stderr, "\n"); 41 | fprintf(stderr, " -s, --openssh Output OpenSSH public and private key\n"); 42 | fprintf(stderr, " The keys are written to id_ed25519{,.pub}\n"); 43 | fprintf(stderr, "\n"); 44 | fprintf(stderr, " -g, --gpg Output OpenPGP public and private key\n"); 45 | fprintf(stderr, " The keys are written to {public,private}.asc\n"); 46 | fprintf(stderr, "\n"); 47 | } 48 | 49 | static struct option options[] = { 50 | // Output Formats. 51 | {"openssh", no_argument, NULL, 's'}, 52 | {"gpg", no_argument, NULL, 'g'}, 53 | 54 | // Key Options. 55 | {"profile", required_argument, NULL, 'p'}, 56 | {"user", required_argument, NULL, 'u'}, 57 | 58 | // Help. 59 | {"help", no_argument, NULL, 'h'}, 60 | 61 | // End of option array: 62 | {NULL, 0, NULL, 0} 63 | }; 64 | 65 | int main(int argc, char *argv[]) 66 | { 67 | int option; 68 | bool success = true; 69 | 70 | // Output formats. 71 | bool ssh_output = false; 72 | bool gpg_output = false; 73 | 74 | // Key options. 75 | char *profile_name = DEFAULT_PROFILE; 76 | 77 | char *username = NULL; 78 | size_t username_length = 0; 79 | 80 | // Output directory. 81 | char *output_directory = "."; 82 | 83 | // Passphrase. 84 | char passphrase[1024]; 85 | char passphrase_verify[sizeof passphrase]; 86 | 87 | // Initialize base64 encoder and decoder. 88 | buffer_init(); 89 | 90 | while ((option = getopt_long(argc, argv, "gshu:p:", options, NULL)) != -1) 91 | { 92 | switch (option) 93 | { 94 | case 's': 95 | ssh_output = true; 96 | break; 97 | 98 | case 'g': 99 | gpg_output = true; 100 | break; 101 | 102 | case 'p': 103 | profile_name = optarg; 104 | break; 105 | 106 | case 'u': 107 | username = optarg; 108 | username_length = strlen(username); 109 | sodium_mlock(username, username_length); 110 | break; 111 | 112 | default: 113 | usage(argv[0]); 114 | return EXIT_FAILURE; 115 | }; 116 | } 117 | 118 | if (argv[optind] != NULL) 119 | { 120 | output_directory = argv[optind]; 121 | } 122 | 123 | // Username is required. 124 | if (username == NULL) 125 | { 126 | fprintf(stderr, "Error: Missing username option ...\n"); 127 | return EXIT_FAILURE; 128 | } 129 | 130 | // We want at least one output format. 131 | if (! (ssh_output || gpg_output)) 132 | { 133 | fprintf(stderr, "Error: Missing output format(s) ...\n"); 134 | return EXIT_FAILURE; 135 | } 136 | 137 | if (! is_valid_profile_name(profile_name)) 138 | { 139 | fprintf(stderr, "Error: Invalid profile '%s' ...\n", profile_name); 140 | return EXIT_FAILURE; 141 | } 142 | 143 | if (sodium_init() == -1) 144 | { 145 | fprintf(stderr, "Error: Unable to initialize libsodium ...\n"); 146 | return EXIT_FAILURE; 147 | } 148 | 149 | sodium_mlock(passphrase, sizeof(passphrase)); 150 | sodium_mlock(passphrase_verify, sizeof(passphrase_verify)); 151 | memory_zero(passphrase, sizeof passphrase); 152 | memory_zero(passphrase_verify, sizeof passphrase); 153 | 154 | if(NULL == readpassphrase("Enter passphrase: ", passphrase, sizeof(passphrase), RPP_ECHO_OFF) 155 | || NULL == readpassphrase("Confirm passphrase: ", passphrase_verify, sizeof(passphrase), RPP_ECHO_OFF)) 156 | { 157 | fprintf(stderr, "Error: Program failed to read passphrases.\n"); 158 | success = false; 159 | goto cleanup_passphrase_and_exit; 160 | } 161 | 162 | if(0 != strncmp(passphrase, passphrase_verify, sizeof(passphrase_verify))) 163 | { 164 | fprintf(stderr, "Error: Passphrases do not match.\n"); 165 | success = false; 166 | goto cleanup_passphrase_and_exit; 167 | } 168 | 169 | if(strlen(passphrase) < 12) 170 | { 171 | fprintf(stderr, "Error: Provided passphrase is shorter than 12 characters.\n"); 172 | success = false; 173 | goto cleanup_passphrase_and_exit; 174 | } 175 | 176 | printf("Generating key material using the '%s' profile ...\n", profile_name); 177 | printf("This may take a little while ...\n"); 178 | 179 | struct profile_t * profile = generate_profile(profile_name, username, passphrase); 180 | 181 | if (ssh_output) 182 | { 183 | if (generate_openssh_keypair(profile)) 184 | { 185 | printf("Successfully generated SSH key pair ...\n"); 186 | // TODO check return val of this or make it a void(*)(..) 187 | openssh_write(output_directory, profile->username, strlen(profile->username), (unsigned char *) &(profile->openssh_secret), (unsigned char *) &(profile->openssh_public)); 188 | } 189 | else 190 | { 191 | fprintf(stderr, "Error: Unable to generate SSH key pair ...\n"); 192 | success = false; 193 | } 194 | } 195 | 196 | if (gpg_output) 197 | { 198 | if (generate_openpgp_keypair(profile)) 199 | { 200 | printf("Successfully generated OpenPGP key pair ...\n"); 201 | if (openpgp_write(output_directory, profile)) 202 | { 203 | printf("Successfully wrote OpenPGP key pair to disk.\n"); 204 | } 205 | else 206 | { 207 | fprintf(stderr, "Failed to write OpenPGP key pair to disk...\n"); 208 | success = false; 209 | } 210 | } 211 | else 212 | { 213 | fprintf(stderr, "Error: Unable to generate GPG key pair ...\n"); 214 | success = false; 215 | } 216 | } 217 | 218 | free_profile_t(profile); 219 | sodium_munlock(username, username_length); 220 | 221 | cleanup_passphrase_and_exit: 222 | sodium_munlock(passphrase, sizeof(passphrase)); 223 | sodium_munlock(passphrase_verify, sizeof(passphrase_verify)); 224 | 225 | return success ? EXIT_SUCCESS : EXIT_FAILURE; 226 | } 227 | -------------------------------------------------------------------------------- /src/memory.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include "memory.h" 10 | 11 | void *secure_malloc(size_t size) 12 | { 13 | void *result = NULL; 14 | 15 | result = sodium_malloc(size); 16 | assert(result != NULL); 17 | 18 | memory_zero(result, size); 19 | 20 | return result; 21 | } 22 | 23 | void secure_free(void *pointer) 24 | { 25 | sodium_free(pointer); 26 | } 27 | 28 | void memory_zero(void *pointer, size_t size) 29 | { 30 | sodium_memzero(pointer, size); 31 | } 32 | 33 | bool memory_equal(void *a, void *b, size_t size) 34 | { 35 | return sodium_memcmp(a, b, size) == 0; 36 | } 37 | 38 | void memory_lock(void *pointer, size_t size) 39 | { 40 | sodium_mlock(pointer, size); 41 | } 42 | 43 | void memory_unlock(void *pointer, size_t size) 44 | { 45 | sodium_munlock(pointer, size); 46 | } 47 | -------------------------------------------------------------------------------- /src/memory.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #ifndef GUARD_MEMORY_H 6 | #define GUARD_MEMORY_H 1 7 | 8 | #include 9 | #include 10 | 11 | void *secure_malloc(size_t size); 12 | void secure_free(void *pointer); 13 | 14 | void memory_zero(void *pointer, size_t size); 15 | bool memory_equal(void *a, void *b, size_t size); 16 | 17 | void memory_lock(void *pointer, size_t size); 18 | void memory_unlock(void *pointer, size_t size); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/openpgp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "openpgp.h" 9 | #include "profile.h" 10 | #include "buffer.h" 11 | #include "buffer_writer.h" 12 | #include "sha.h" 13 | 14 | // our OpenPGP constants 15 | #define PGP_single_octet_length 0 16 | #define PGP_signature_subpacket_is_critical 0x80 17 | #define PGP_hardcoded_timestamp 0x58606060L 18 | #define PGP_ed25519_oid "\x2B\x06\x01\x04\x01\xDA\x47\x0F\x01" 19 | #define PGP_ed25519_oid_size 9 20 | #define PGP_public_file_name "/public.asc" 21 | #define PGP_secret_file_name "/secret.asc" 22 | 23 | typedef enum { PUBLIC_KEY, PRIVATE_KEY } PGP_key_type_t; 24 | 25 | typedef struct __attribute__((__packed__)) pkt_header 26 | { 27 | uint8_t length_type : 2; // codes for length field size; 0 is for single-octet length 28 | uint8_t packet_tag : 4; 29 | uint8_t new_format : 1; 30 | uint8_t always_one : 1; 31 | } pkt_header; 32 | 33 | static uint16_t mpi_len(unsigned char msb) 34 | { 35 | // This function takes the most significant byte and 36 | // returns (256 minus count of leading unset bits) 37 | // The libgcrypt MPI format prefixes big-endian integers with a uint16 specifying the 38 | // number of bits required to represent the integer. 39 | // We could hardcode "256", but that eveals our keys as being made by passphrase-identity, 40 | // so we have to adhere to the bit-counting MPI encoding that libgcrypt uses. 41 | uint16_t bits_not_set = 0; 42 | for(int c=0x80; ~msb & c; c>>=1 ) 43 | { 44 | bits_not_set++; 45 | } 46 | return 256 - bits_not_set; 47 | } 48 | 49 | static bool crc24_bytes(unsigned char *octets, size_t len, uint8_t output[3]) 50 | { 51 | // Adapted from 6.1 An Implementation of the CRC-24 in "C" 52 | // https://tools.ietf.org/html/rfc4880#section-6.1 53 | 54 | if(NULL == octets || NULL == output || 0 == len) 55 | return false; 56 | 57 | int32_t crc = 0xB704CEL; 58 | 59 | while (len--) 60 | { 61 | crc ^= (*octets++) << 16; 62 | for (int i = 0; i < 8; i++) 63 | { 64 | crc <<= 1; 65 | if (crc & 0x1000000) 66 | crc ^= 0x1864CFBL; 67 | } 68 | } 69 | 70 | crc = htonl(crc & 0xffffff); 71 | output[0] = (crc >>= 8) & 0xff; 72 | output[1] = (crc >>= 8) & 0xff; 73 | output[2] = (crc >>= 8) & 0xff; 74 | 75 | return true; 76 | } 77 | 78 | static struct buffer * openpgp_encode_armor(const struct buffer *input, PGP_key_type_t key_type) 79 | { 80 | // 6. Radix-64 Conversions: 81 | // https://tools.ietf.org/html/rfc4880#section-6 82 | 83 | // "OpenPGP's Radix-64 encoding is composed of two parts: a base64 84 | // encoding of the binary data and a checksum. The base64 encoding is 85 | // identical to the MIME base64 content-transfer-encoding [RFC2045]." 86 | 87 | bool ok = true; 88 | 89 | struct buffer * b64 = NULL; 90 | struct buffer * crc_raw = NULL; 91 | struct buffer * crc_b64 = NULL; 92 | struct buffer * output_buf = NULL; 93 | buffer_writer_t * output = NULL; 94 | 95 | if(NULL == input) 96 | goto error; 97 | 98 | // When OpenPGP encodes data into ASCII Armor, it puts specific headers 99 | // around the Radix-64 encoded data, so OpenPGP can reconstruct the data 100 | // later. An OpenPGP implementation MAY use ASCII armor to protect raw 101 | // binary data. OpenPGP informs the user what kind of data is encoded 102 | // in the ASCII armor through the use of the headers. 103 | 104 | ok &= buffer_base64_encode(input, &b64); 105 | 106 | output_buf = buffer_new(buffer_size(b64) + 400); 107 | output = buffer_writer_new(output_buf); 108 | if(NULL == output) goto error; 109 | 110 | crc_raw = buffer_new(3); 111 | if(NULL == crc_raw) goto error; 112 | ok &= crc24_bytes(input->data, input->size, crc_raw->data); 113 | ok &= buffer_base64_encode(crc_raw, &crc_b64); 114 | 115 | if(!ok) goto error; 116 | 117 | // - An Armor Header Line, appropriate for the type of data 118 | 119 | ok &= buffer_writer_write_asciiz(output, "-----BEGIN PGP "); 120 | if(PUBLIC_KEY == key_type) 121 | ok &= buffer_writer_write_asciiz(output, "PUBLIC"); 122 | if(PRIVATE_KEY == key_type) 123 | ok &= buffer_writer_write_asciiz(output, "PRIVATE"); 124 | ok &= buffer_writer_write_asciiz(output, " KEY BLOCK-----\n"); 125 | 126 | // Blatantly lie about our user-agent: 127 | ok &= buffer_writer_write_asciiz(output, "Version: GnuPG v2\n\n"); 128 | 129 | // Note that line lengths of the "Radix 64" (aka Base64) flavour specified is 76, 130 | // but we use 64 to be as similar to GnuPG as possible. 131 | // "6.3. Encoding Binary in Radix-64" (bottom paragraph): 132 | // https://tools.ietf.org/html/rfc4880#section-6.3 133 | 134 | ok &= buffer_writer_write_asciiz_with_linewrapping(output, (const char *) b64->data, 64); 135 | 136 | if(ok && '\n' != output->buffer->data[output->write_offset-1]) 137 | { 138 | ok &= buffer_writer_write_asciiz(output, "\n"); 139 | } 140 | 141 | ok &= buffer_writer_write_value(output, crc_b64->data, crc_b64->size); 142 | ok &= buffer_writer_write_asciiz(output, "\n"); 143 | 144 | ok &= buffer_writer_write_asciiz(output, "-----END PGP "); 145 | if(PUBLIC_KEY == key_type) 146 | ok &= buffer_writer_write_asciiz(output, "PUBLIC"); 147 | if(PRIVATE_KEY == key_type) 148 | ok &= buffer_writer_write_asciiz(output, "PRIVATE"); 149 | ok &= buffer_writer_write_asciiz(output, " KEY BLOCK-----\n"); 150 | 151 | goto cleanup; 152 | 153 | error: 154 | ok = false; 155 | 156 | cleanup: 157 | 158 | if(ok) 159 | { 160 | output_buf->size = output->write_offset; 161 | }else 162 | { 163 | buffer_free(output_buf); 164 | output_buf = NULL; 165 | } 166 | 167 | buffer_free(b64); 168 | buffer_free(crc_raw); 169 | buffer_free(crc_b64); 170 | buffer_writer_free(output); 171 | 172 | return output_buf; 173 | } 174 | 175 | static bool openpgp_keyid_from_profile(const struct profile_t * profile, char keyid[8]) 176 | { 177 | // TODO reference rfc 4880 spec section 178 | // loosely based on 179 | // gnupg2: g10/keyid.c:keyid_from_pk() 180 | // basically this is the rightmost 8 bytes of the sha1sum of 181 | // the output of g10/keyid.c:hash_public_key() 182 | 183 | if(NULL == profile || NULL == keyid) 184 | { 185 | return false; 186 | } 187 | 188 | struct buffer *tmp_buf = NULL; 189 | buffer_writer_t *buf = NULL; 190 | 191 | bool ok = true; 192 | 193 | // version+time+pk_algo + oid_len+oid + mpi_bits+curve_flags+point_A 194 | const size_t msg_length = 1+4+1 + 1+1+strlen(PGP_ed25519_oid) + 1+1+32; 195 | 196 | // length including header: magic_uint8 + len_uint16 + msg_length 197 | tmp_buf = buffer_new(1+2 + msg_length); 198 | buf = buffer_writer_new(tmp_buf); 199 | 200 | // TODO "CTB" magic aka signature type /header type 201 | ok &= buffer_writer_write_uint8(buf, 0x99); 202 | // length of this pkt (not including the header): 203 | ok &= buffer_writer_write_uint16(buf, msg_length); 204 | 205 | // openpgp format version: 206 | ok &= buffer_writer_write_uint8(buf, 0x04); 207 | 208 | // timestamp 209 | ok &= buffer_writer_write_uint32(buf, PGP_hardcoded_timestamp); 210 | 211 | // pubkey algo: https://tools.ietf.org/html/draft-koch-eddsa-for-openpgp-04#section-8 212 | ok &= buffer_writer_write_uint8(buf, 0x16); 213 | 214 | ok &= buffer_writer_write_uint8(buf, strlen(PGP_ed25519_oid)); 215 | ok &= buffer_writer_write_asciiz(buf, PGP_ed25519_oid); 216 | 217 | // write public key. see comments in openpgp_fill_public_key for details 218 | ok &= buffer_writer_write_uint16(buf, 0x0107); 219 | ok &= buffer_writer_write_uint8(buf, 0x40); 220 | ok &= buffer_writer_write_value(buf, profile->openpgp_public, sizeof(profile->openpgp_public)); 221 | 222 | SHA1Context sha1_ctx; 223 | uint8_t pk_hash[SHA1HashSize]; 224 | 225 | ok &= shaSuccess == SHA1Reset(&sha1_ctx); 226 | if(!ok) goto cleanup; 227 | ok &= shaSuccess == SHA1Input(&sha1_ctx, tmp_buf->data, tmp_buf->size); 228 | if(!ok) goto cleanup; 229 | ok &= shaSuccess == SHA1Result(&sha1_ctx, pk_hash); 230 | if(!ok) goto cleanup; 231 | 232 | memcpy(keyid, pk_hash+sizeof(pk_hash)-8, 8); 233 | memcpy(keyid, pk_hash+12, 8); 234 | 235 | cleanup: 236 | buffer_free(tmp_buf); 237 | buffer_writer_free(buf); 238 | 239 | sodium_memzero(&sha1_ctx, sizeof sha1_ctx); 240 | sodium_memzero(&pk_hash, sizeof pk_hash); 241 | 242 | return ok; 243 | } 244 | 245 | static struct buffer * openpgp_transferable_public_or_secret_key_packet(const profile_t *profile, PGP_key_type_t key_type) 246 | { 247 | // 5.5.1.1. Public-Key Packet (Tag 6) 248 | // 5.5.1.3. Secret-Key Packet (Tag 5) 249 | struct buffer *key_packet = NULL; 250 | struct buffer_writer *pkp_w = NULL; 251 | 252 | bool ok = true; 253 | 254 | /* sizeof(uint8_t) // Version 255 | + sizeof(uint32_t) // Timestamp 256 | + sizeof(uint8_t) // Public-key algorithm 257 | + sizeof(uint8_t) // Length of curve point 258 | + PGP_ed25519_oid_size // Curve point 259 | + sizeof(uint16_t) // MPI length field for EdDSA "A" 260 | + sizeof(uint8_t) // point compression type 261 | + sizeof profile->openpgp_public 262 | + (PUBLIC_KEY == key_type ? 0 : ( 263 | sizeof(uint8_t) // "string-to-key" usage AKA "DO YOU ENCRYPT?!" 264 | + sizeof(uint16_t) // MPI length field for EdDSA "ENC(X,Y)" 265 | + sizeof(profile->openpgp_secret) // the seed "d" for EdDSA secret key 266 | + sizeof(uint16_t) // the "sum all the bytes" checksum" 267 | ) 268 | ); 269 | */ 270 | #define pgp_public_packet_msg_length \ 271 | ( sizeof(uint8_t) \ 272 | + sizeof(uint32_t) \ 273 | + sizeof(uint8_t) \ 274 | + sizeof(uint8_t) \ 275 | + PGP_ed25519_oid_size \ 276 | + sizeof(uint16_t) \ 277 | + sizeof(uint8_t) \ 278 | + sizeof(profile->openpgp_public) \ 279 | ) 280 | #define pgp_private_packet_msg_length \ 281 | ( \ 282 | pgp_public_packet_msg_length \ 283 | + sizeof(uint8_t) \ 284 | + sizeof(uint16_t) \ 285 | + sizeof(profile->openpgp_secret) \ 286 | + sizeof(uint16_t) \ 287 | ) 288 | 289 | const uint16_t msg_length = (PUBLIC_KEY == key_type) ? pgp_public_packet_msg_length : pgp_private_packet_msg_length; 290 | 291 | key_packet = buffer_new(sizeof(struct pkt_header)+sizeof(uint8_t)+msg_length); 292 | pkp_w = buffer_writer_new(key_packet); 293 | 294 | struct pkt_header packet_header = 295 | { 296 | .always_one = 1, 297 | .new_format = 0, 298 | .packet_tag = 0, 299 | .length_type = PGP_single_octet_length 300 | }; 301 | 302 | if(PUBLIC_KEY == key_type) 303 | // 5.5.1.1. Public-Key Packet (Tag 6) 304 | packet_header.packet_tag = 6; 305 | 306 | if(PRIVATE_KEY == key_type) 307 | // 5.5.1.3. Secret-Key Packet (Tag 5) 308 | packet_header.packet_tag = 5; 309 | 310 | ok &= buffer_writer_write_value(pkp_w, &packet_header, sizeof(packet_header)); 311 | 312 | // length of this packet: 313 | assert(msg_length < 192); // TODO 314 | ok &= buffer_writer_write_uint8(pkp_w, msg_length); 315 | 316 | // see: 5.5.2. Public-Key Packet Formats: 317 | 318 | // version: (version 4) 319 | ok &= buffer_writer_write_uint8(pkp_w, 0x04); 320 | 321 | // timestamp (created): 322 | ok &= buffer_writer_write_uint32(pkp_w, PGP_hardcoded_timestamp); 323 | 324 | // public-key algorithm of key; that is EdDSA, see: 325 | // https://tools.ietf.org/html/draft-koch-eddsa-for-openpgp-04#section-8 326 | // and https://tools.ietf.org/html/rfc6637 327 | // and eventually https://tools.ietf.org/html/rfc4880#section-9.1 328 | ok &= buffer_writer_write_uint8(pkp_w, 0x16); 329 | 330 | // length of curve point / OID (in bytes): 331 | ok &= buffer_writer_write_uint8(pkp_w, 9); 332 | // Ed25519 OID: https://tools.ietf.org/html/draft-koch-eddsa-for-openpgp-04#section-6 333 | ok &= buffer_writer_write_value(pkp_w, PGP_ed25519_oid, strlen(PGP_ed25519_oid)); 334 | 335 | // MPI of an EC point representing a public key Q, length in bits (=0x107=263=256+7) 336 | // equivalent to: mpi_len(0x40) + 8 337 | ok &= buffer_writer_write_uint16(pkp_w, 0x0107); 338 | 339 | // Point Compression flag byte: 0x40 Native point format of the curve follows: 340 | // see https://tools.ietf.org/html/draft-koch-eddsa-for-openpgp-04#appendix-B 341 | ok &= buffer_writer_write_uint8(pkp_w, 0x40); 342 | 343 | // public key element "Q" 344 | ok &= buffer_writer_write_value(pkp_w, profile->openpgp_public, sizeof profile->openpgp_public); 345 | 346 | if(PRIVATE_KEY == key_type) 347 | { 348 | // Secret-Key Packet Formats https://tools.ietf.org/html/rfc4880#section-5.5.3 349 | 350 | // for more pointers to what is going on here I suggest looking at gnupg src: 351 | // g10/packet.h:struct seckey_info 352 | // g10/import.c:transfer_secret_keys() 353 | // g10/export.c:transfer_format_to_openpgp() - validation stub 354 | // agent/command.c:cmd_import_key() - where it actually imports stuff 355 | // agent/cvt-xx : do_unprotect() - where the checksum/"actual_csum" is calculated 356 | 357 | // "One octet indicating string-to-key usage conventions. 358 | // Zero indicates that the secret-key data is not encrypted. 359 | // 255 or 254 indicates that a string-to-key specifier is being given. 360 | // Any other value is a symmetric-key encryption algorithm identifier. 361 | 362 | ok &= buffer_writer_write_uint8(pkp_w, 0x00); 363 | 364 | // from gnupg src: Append the secret key element D. 365 | // NB this is what libsodium calls a "seed" - GPG hashes it 366 | // every time it makes a signature 367 | 368 | // from https://tools.ietf.org/html/draft-koch-eddsa-for-openpgp-04#section-4 369 | // The following algorithm specific packets are added to Section 5.5.3 370 | // of [RFC4880], "Secret-Key Packet Formats", to support EdDSA. 371 | // Algorithm-Specific Fields for EdDSA keys: 372 | // o an MPI of an integer representing the secret key, which is a 373 | // scalar of the public EC point. 374 | 375 | uint16_t mpi_length = mpi_len(*profile->openpgp_secret); 376 | 377 | ok &= buffer_writer_write_uint16(pkp_w, mpi_length); 378 | 379 | ok &= buffer_writer_write_value(pkp_w, profile->openpgp_secret, sizeof(profile->openpgp_secret)); 380 | 381 | // If the string-to-key usage octet is zero or 255, then a two-octet 382 | // checksum of the plaintext of the algorithm-specific portion (sum 383 | // of all octets, mod 65536): 384 | if(ok) 385 | { 386 | uint16_t checksum = 0; 387 | checksum += mpi_length & 0xff; 388 | checksum += mpi_length >> 8; 389 | for(uint8_t i = 0; i < 32; i++) 390 | { 391 | checksum += *(i + profile->openpgp_secret); 392 | } 393 | ok &= buffer_writer_write_uint16(pkp_w, checksum); 394 | } 395 | } 396 | 397 | if(ok) 398 | { 399 | // limit size so we can rely on ->size 400 | if(key_packet->size > pkp_w->write_offset) 401 | key_packet->size = pkp_w->write_offset; 402 | } 403 | else 404 | { 405 | buffer_free(key_packet); 406 | key_packet = NULL; 407 | } 408 | 409 | buffer_writer_free(pkp_w); 410 | 411 | return key_packet; 412 | } 413 | 414 | static struct buffer * openpgp_fill_key(const profile_t * profile, PGP_key_type_t key_type) 415 | { 416 | if(NULL == profile 417 | || NULL == profile->username) 418 | return NULL; 419 | 420 | struct buffer *public_key_packet = NULL; 421 | 422 | struct buffer *uid_packet = NULL; 423 | struct buffer_writer *uid_w = NULL; 424 | 425 | struct buffer *headless_signature_packet = NULL; 426 | buffer_writer_t *sig_w = NULL; 427 | 428 | struct buffer *signature_unhashed_subpacket = NULL; 429 | buffer_writer_t *unhashed_w = NULL; 430 | 431 | struct buffer *output = NULL; 432 | buffer_writer_t *output_w = NULL; 433 | 434 | struct buffer *tobehashed = NULL; 435 | buffer_writer_t * tbh = NULL; 436 | 437 | struct buffer * sig_subpacket = NULL; 438 | buffer_writer_t * sig_subpacket_w = NULL; 439 | 440 | bool ok = true; 441 | 442 | struct pkt_header packet_header = 443 | { 444 | .always_one = 1, 445 | .new_format = 0, 446 | .packet_tag = 0, 447 | .length_type = PGP_single_octet_length 448 | }; 449 | 450 | ////// 5.5.1.1. Public-Key Packet (Tag 6) 451 | 452 | public_key_packet = openpgp_transferable_public_or_secret_key_packet(profile, key_type); 453 | if(NULL == public_key_packet) 454 | { 455 | ok = false; 456 | goto cleanup; 457 | } 458 | 459 | ////// rfc 4880 section 5.11: User ID Packet (tag 13): 460 | uid_packet = buffer_new(sizeof(packet_header) + sizeof(uint8_t) + strlen(profile->username)); 461 | 462 | uid_w = buffer_writer_new(uid_packet); 463 | 464 | packet_header.packet_tag = 13; 465 | ok &= buffer_writer_write_value(uid_w, &packet_header, sizeof(packet_header)); 466 | ok &= buffer_writer_write_uint8(uid_w, strlen(profile->username)); 467 | ok &= buffer_writer_write_value(uid_w, profile->username, strlen(profile->username)); 468 | 469 | ////// rfc4880: Version 4 Signature Packet Format: https://tools.ietf.org/html/rfc4880#section-5.2.3 470 | // see gnupg2 source code: g10/sign.c:make_keysig_packet() 471 | // g10/parse-packet.c:parse_signature() 472 | // g10/:do_signature() 473 | // TODO agent_pksign 474 | // also see the PKT_signature struct 475 | 476 | headless_signature_packet = buffer_new(1000); 477 | 478 | sig_w = buffer_writer_new(headless_signature_packet); 479 | 480 | // version: (version 4) 481 | // gnupg2: sig->sig_version 482 | ok &= buffer_writer_write_uint8(sig_w, 0x04); 483 | // signature class: 0x13: Positive certification of a User ID and Public-Key packet. 484 | // see https://tools.ietf.org/html/rfc4880#section-5.2.1 485 | // gnupg2: sig->sig_class 486 | ok &= buffer_writer_write_uint8(sig_w, 0x13); 487 | // See comment about "public-key algorithm of key" (but basically - ed25519): 488 | // gnupg2: sig->sig_pubkey_algo 489 | ok &= buffer_writer_write_uint8(sig_w, 0x16); 490 | // Hashing-algorithm: SHA256 (see https://tools.ietf.org/html/rfc4880#section-9.4): 491 | // gnupg2: sig->sig_digest_algo 492 | ok &= buffer_writer_write_uint8(sig_w, 0x08); 493 | 494 | //// 5.2.3.1. Signature Subpacket Specification (zero or more subpackets) 495 | // - subpacket length (1; 2; 5 octets) (if <192: 1) 496 | // - subpacket type (1 octet) 497 | 498 | // Bit 7 of the subpacket type is the "critical" bit. If set, it 499 | // denotes that the subpacket is one that is critical for the evaluator 500 | // of the signature to recognize. If a subpacket is encountered that is 501 | // marked critical but is unknown to the evaluating software, the 502 | // evaluator SHOULD consider the signature to be in error. 503 | 504 | sig_subpacket = buffer_new(1000); 505 | sig_subpacket_w = buffer_writer_new(sig_subpacket); 506 | 507 | // length: 508 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x05); 509 | // 2: Signature Creation Time: https://tools.ietf.org/html/rfc4880#section-5.2.3.4 510 | // see build_sig_subpkt_from_sig(), build_sig_subpkt( sig, SIGSUBPKT_SIG_CREATED, ..) 511 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x02); 512 | // timestamp: 513 | ok &= buffer_writer_write_uint32(sig_subpacket_w, PGP_hardcoded_timestamp); 514 | 515 | // length: 516 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x02); 517 | // 27: Key Flags: https://tools.ietf.org/html/rfc4880#section-5.2.3.21 518 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x1b); 519 | // flags: 520 | // 0x01 - This key may be used to certify other keys. 521 | // 0x02 - This key may be used to sign data. 522 | // NOT SET: 0x04 - This key may be used to encrypt communications. 523 | // 0x20 - This key may be used for authentication. 524 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x23); 525 | 526 | // length: 527 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x05); 528 | // 11 = Preferred Symmetric Algorithms: https://tools.ietf.org/html/rfc4880#section-5.2.3.7 529 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x0b); 530 | // list of legal values: https://tools.ietf.org/html/rfc4880#section-9.2 531 | // 9 - AES with 256-bit key: 532 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x09); 533 | // 8 - AES with 192-bit key: 534 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x08); 535 | // 7 - AES with 128-bit key: 536 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x07); 537 | // 2 - TripleDES (DES-EDE, [SCHNEIER] [HAC] 168 bit key derived from 192) 538 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x02); 539 | 540 | // length: 541 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x06); 542 | // 21 = Preferred Hash Algorithms: https://tools.ietf.org/html/rfc4880#section-5.2.3.8 543 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x15); 544 | // list of legal values: https://tools.ietf.org/html/rfc4880#section-9.2 545 | // 8 - SHA256: 546 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x08); 547 | // 9 - SHA384: 548 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x09); 549 | // 10 - SHA512: 550 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x0a); 551 | // 11 - SHA224: 552 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x0b); 553 | // 2 - SHA-1: 554 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x02); 555 | 556 | // length: 557 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x04); 558 | // 22 = Preferred Compression Algorithms: https://tools.ietf.org/html/rfc4880#section-5.2.3.9 559 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x16); 560 | // list of legal values:https://tools.ietf.org/html/rfc4880#section-9.3 561 | // 2 - ZLIB rfc 1950 562 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x02); 563 | // 3 - Bzip2 564 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x03); 565 | // 1 - ZIP rfc 1951 566 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x01); 567 | 568 | // length: 569 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x02); 570 | // 30 = Features: https://tools.ietf.org/html/rfc4880#section-5.2.3.24 571 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x1e); 572 | // 0x01 - Modification Detection (packets 18 and 19): 573 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x01); 574 | 575 | // length: 576 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x02); // 26 577 | // 23 = Key Server Preferences: https://tools.ietf.org/html/rfc4880#section-5.2.3.17 578 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x17); 579 | // First octet: 0x80 = No-modify 580 | // the key holder requests that this key only be modified or updated 581 | // by the key holder or an administrator of the key server. 582 | ok &= buffer_writer_write_uint8(sig_subpacket_w, 0x80); 583 | 584 | //// UNHASHED SUBPACKET DATA: 585 | 586 | signature_unhashed_subpacket = buffer_new(1000); 587 | 588 | unhashed_w = buffer_writer_new(signature_unhashed_subpacket); 589 | 590 | // - Two-octet scalar octet count for the following unhashed subpacket 591 | // data. Note that this is the length in octets of all of the 592 | // unhashed subpackets; a pointer incremented by this number will 593 | // skip over the unhashed subpackets. 594 | ok &= buffer_writer_write_uint16(unhashed_w, 10); 595 | 596 | // subpacket length: 597 | ok &= buffer_writer_write_uint8(unhashed_w, 9); 598 | // 16 = Issuer: https://tools.ietf.org/html/rfc4880#section-5.2.3.5 599 | ok &= buffer_writer_write_uint8(unhashed_w, 0x10); 600 | // 8-octets: The OpenPGP Key ID of the key issuing the signature. 601 | //uint8_t pk_keyid[8]; 602 | char pk_keyid[8]; 603 | sodium_memzero(&pk_keyid, sizeof pk_keyid); 604 | ok &= openpgp_keyid_from_profile(profile, pk_keyid); 605 | if(!ok) goto cleanup; 606 | 607 | ok &= buffer_writer_write_value(unhashed_w, pk_keyid, sizeof pk_keyid); 608 | 609 | //// continue the signature packet (this marks end of unhashed subpacket data) 610 | if(!ok) goto cleanup; 611 | 612 | // Two-octet scalar octet count for the following HASHED subpacket data. 613 | ok &= buffer_writer_write_uint16(sig_w, sig_subpacket_w->write_offset); 614 | 615 | ok &= buffer_writer_write_buffer(sig_w, sig_subpacket_w); 616 | 617 | unsigned char signature_hash[crypto_hash_sha256_BYTES]; 618 | tobehashed = buffer_new(1000); 619 | tbh = buffer_writer_new(tobehashed); 620 | 621 | // see 5.2.4 Computing Signatures - https://tools.ietf.org/html/rfc4880#section-5.2.4 622 | // signature_type ("over a key") 623 | ok &= buffer_writer_write_uint8(tbh, 0x99); 624 | // two-octet length of the public key packet body 625 | ok &= buffer_writer_write_uint16(tbh, pgp_public_packet_msg_length); 626 | 627 | // - hash the public key certificate: hash_public_key() 628 | ok &= buffer_writer_write_value(tbh, 2+public_key_packet->data, pgp_public_packet_msg_length); 629 | 630 | // - hash the uid: hash_uid() 631 | // "A V4 certification hashes the constant 0xB4 for User ID certifications" 632 | ok &= buffer_writer_write_uint8(tbh, 0xB4); 633 | // "followed by a four-octet number giving the length of the User ID" 634 | ok &= buffer_writer_write_uint32(tbh, *(1+uid_w->buffer->data)); 635 | ok &= buffer_writer_write_value(tbh, 2+uid_w->buffer->data, uid_w->write_offset-2); 636 | 637 | // - hash this pkt so far: first part of hash_sigversion_to_magic() 638 | ok &= buffer_writer_write_buffer(tbh, sig_w); 639 | 640 | crypto_hash_sha256_state sha256_state; 641 | 642 | // construct the magic part two of hash_sigversion_to_magic(): (wtf openpgp) 643 | // "V4 signatures also hash in a final trailer of six octets" ... 644 | // sig->version 645 | ok &= buffer_writer_write_uint8(tbh, 0x04); 646 | // len of hashed part of signature packet so far, 647 | // in the OpenPGP 5-octet length format: 648 | // if the 1st octet = 255, then 649 | // lengthOfLength = 5 650 | // subpacket length = [four-octet scalar starting at 2nd_octet] 651 | ok &= buffer_writer_write_uint8(tbh, 0xFF); 652 | ok &= buffer_writer_write_uint32(tbh, sig_w->write_offset); 653 | 654 | ok &= 0== crypto_hash_sha256_init(&sha256_state); 655 | if(!ok) goto cleanup; 656 | ok &= 0== crypto_hash_sha256_update(&sha256_state, tobehashed->data, tbh->write_offset); 657 | if(!ok) goto cleanup; 658 | ok &= 0== crypto_hash_sha256_final(&sha256_state, signature_hash); 659 | if(!ok) goto cleanup; 660 | 661 | //// now that we are done computing the hash, add the un-MAC'ed subpackets: 662 | 663 | ok &= buffer_writer_write_buffer(sig_w, unhashed_w); 664 | 665 | // - Two-octet field holding left 16 bits of signed hash value. 666 | // NB: "signed hash value" AKA "ecc_verify data:" field 667 | // when running gpg --debug-level guru --import 668 | ok &= buffer_writer_write_uint8(sig_w, signature_hash[0]); 669 | ok &= buffer_writer_write_uint8(sig_w, signature_hash[1]); 670 | 671 | // - "One or more multiprecision integers comprising the signature." 672 | // in Ed25519 EdDSA it's the R and S values from 673 | // https://tools.ietf.org/html/rfc8032#section-3.3 674 | // so this is where we pray that libsodium implements this: 675 | // Let R = [r]B and S = (r + H(ENC(R) || ENC(A) || PH(M)) * s) mod L 676 | // and that we use this encoding: https://tools.ietf.org/html/rfc8032#section-3.1 677 | 678 | struct __attribute__((__packed__)) 679 | { 680 | char r[32]; 681 | char s[32]; 682 | } ed25519_sig; 683 | 684 | // TODO consider using crypto_sign_ed25519_sk_to_seed() instead 685 | unsigned char *tmp_secret = sodium_malloc(64); 686 | ok &= NULL != tmp_secret; 687 | if(!ok) goto cleanup; 688 | 689 | ok &= 0== crypto_sign_ed25519_seed_keypair(32+tmp_secret, tmp_secret, profile->openpgp_secret); 690 | if(!ok) goto zero_secret; 691 | 692 | ok &= 0== crypto_sign_ed25519_detached((unsigned char *)&ed25519_sig, NULL, signature_hash, sizeof signature_hash, tmp_secret); 693 | 694 | zero_secret: 695 | sodium_free(tmp_secret); 696 | if(!ok) goto cleanup; 697 | 698 | // size of EdDSA "R" in bits: https://tools.ietf.org/html/rfc6637#section-6 699 | ok &= buffer_writer_write_uint16(sig_w, mpi_len(*ed25519_sig.r)); 700 | ok &= buffer_writer_write_value(sig_w, ed25519_sig.r, sizeof ed25519_sig.r); 701 | 702 | // size of EdDSA "S" in bits: 703 | ok &= buffer_writer_write_uint16(sig_w, mpi_len(*ed25519_sig.s)); 704 | ok &= buffer_writer_write_value(sig_w, ed25519_sig.s, sizeof ed25519_sig.s); 705 | 706 | ////// assemble our three packets into a single buffer: 707 | 708 | output = buffer_new( 709 | 2 // make space for the sig_w two-byte header 710 | + buffer_size(public_key_packet) 711 | + uid_w->write_offset 712 | + sig_w->write_offset 713 | ); 714 | 715 | output_w = buffer_writer_new(output); 716 | 717 | ok &= buffer_writer_write_value(output_w, public_key_packet->data, buffer_size(public_key_packet)); 718 | ok &= buffer_writer_write_buffer(output_w, uid_w); 719 | 720 | //// give headless_signature_packet a head 721 | packet_header.packet_tag = 2; 722 | ok &= buffer_writer_write_value(output_w, &packet_header, sizeof(packet_header)); 723 | // one-octet pkt length: 724 | // assert(192 > buffer_size(headless_signature_packet)); 725 | ok &= buffer_writer_write_uint8(output_w, sig_w->write_offset); 726 | ok &= buffer_writer_write_buffer(output_w, sig_w); 727 | 728 | cleanup: 729 | // - the writer for public_key_packet gets cleaned up in its own function 730 | buffer_writer_free(uid_w); 731 | buffer_writer_free(sig_w); 732 | buffer_writer_free(output_w); 733 | buffer_writer_free(unhashed_w); 734 | buffer_writer_free(tbh); 735 | 736 | buffer_free(public_key_packet); 737 | buffer_free(uid_packet); 738 | buffer_free(headless_signature_packet); 739 | buffer_free(sig_subpacket); 740 | buffer_free(signature_unhashed_subpacket); 741 | buffer_free(tobehashed); 742 | 743 | sodium_memzero(signature_hash, sizeof(signature_hash)); 744 | sodium_memzero(&sha256_state, sizeof(sha256_state)); 745 | sodium_memzero(&ed25519_sig, sizeof(ed25519_sig)); 746 | 747 | if(ok) 748 | { 749 | return output; 750 | } 751 | 752 | buffer_free(output); 753 | return NULL; 754 | } 755 | 756 | // Transferable Secret Keys: 757 | // https://tools.ietf.org/html/rfc4880#section-11.2 758 | // The format of a transferable 759 | // secret key is the same as a transferable public key except that 760 | // secret-key and secret-subkey packets are used instead of the public 761 | // key and public-subkey packets. 762 | 763 | // 5.5.1.3. Secret-Key Packet (Tag 5) 764 | // A Secret-Key packet contains all the information that is found in a 765 | // Public-Key packet, including the public-key material, but also 766 | // includes the secret-key material after all the public-key fields. 767 | 768 | // Algorithm-Specific Fields for EdDSA keys: 769 | // o an MPI of an integer representing the secret key, which is a 770 | // scalar of the public EC point. 771 | 772 | // 5.5.1.4. Secret-Subkey Packet (Tag 7) 773 | 774 | // A Secret-Subkey packet (tag 7) is the subkey analog of the Secret 775 | // Key packet and has exactly the same format. 776 | 777 | bool openpgp_write(const char *output_directory, const struct profile_t *profile) 778 | { 779 | if(NULL == profile || NULL == output_directory) 780 | return false; 781 | 782 | // since we're going to display error messages, reset errno to avoid 783 | // describing previous errors: 784 | errno = 0; 785 | 786 | FILE * fh = NULL; 787 | bool ok = true; 788 | 789 | struct buffer * public_data = NULL; 790 | struct buffer * secret_data = NULL; 791 | struct buffer * ascii_public_data = NULL; 792 | struct buffer * ascii_secret_data = NULL; 793 | char * public_path = NULL; 794 | char * secret_path = NULL; 795 | 796 | public_data = openpgp_fill_key(profile, PUBLIC_KEY); 797 | ascii_public_data = openpgp_encode_armor(public_data, PUBLIC_KEY); 798 | if(NULL == ascii_public_data) goto error; 799 | 800 | public_path = malloc(strlen(output_directory) + strlen(PGP_public_file_name) + 1); 801 | if(NULL == public_path) goto error; 802 | strcpy(public_path, output_directory); 803 | strcat(public_path, PGP_public_file_name); 804 | 805 | fh = fopen(public_path, "wcx"); 806 | if(NULL == fh) goto error; 807 | if(1 != fwrite(ascii_public_data->data, ascii_public_data->size, 1, fh)) goto error; 808 | if(0 != fclose(fh)) goto error; 809 | 810 | secret_data = openpgp_fill_key(profile, PRIVATE_KEY); 811 | ascii_secret_data = openpgp_encode_armor(secret_data, PRIVATE_KEY); 812 | if(NULL == ascii_secret_data) goto error; 813 | 814 | secret_path = malloc(strlen(output_directory) + strlen(PGP_secret_file_name) + 1); 815 | if(NULL == secret_path) goto error; 816 | strcpy(secret_path, output_directory); 817 | strcat(secret_path, PGP_secret_file_name); 818 | 819 | fh = fopen(secret_path, "wcx"); 820 | if(NULL == fh) goto error; 821 | if(1 != fwrite(ascii_secret_data->data, ascii_secret_data->size, 1, fh)) goto error; 822 | if(0 != fclose(fh)) goto error; 823 | 824 | goto cleanup; 825 | 826 | error: 827 | ok = false; 828 | 829 | if(errno) 830 | perror("OpenPGP error"); 831 | 832 | cleanup: 833 | buffer_free(public_data); 834 | buffer_free(secret_data); 835 | buffer_free(ascii_public_data); 836 | buffer_free(ascii_secret_data); 837 | free(public_path); 838 | free(secret_path); 839 | 840 | return ok; 841 | } 842 | -------------------------------------------------------------------------------- /src/openpgp.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #ifndef GUARD_OPENPGP_H 6 | #define GUARD_OPENPGP_H 1 7 | 8 | #include "profile.h" 9 | #include 10 | 11 | bool openpgp_write(const char *output_directory, const struct profile_t *profile); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/openssh.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "buffer.h" 13 | #include "buffer_writer.h" 14 | #include "openssh.h" 15 | 16 | #include 17 | 18 | static bool openssh_write_public(const char *output_directory, const char *username, size_t username_length, unsigned char *public) 19 | { 20 | // Public key file. 21 | char *public_file_path = NULL; 22 | int fd = 0; 23 | 24 | if (output_directory != NULL) 25 | { 26 | size_t public_file_path_len = strlen(output_directory) + 16; 27 | public_file_path = malloc(public_file_path_len); 28 | snprintf(public_file_path, public_file_path_len, "%s/id_ed25519.pub", output_directory); 29 | } 30 | else 31 | public_file_path = strdup("id_ed25519.pub"); 32 | 33 | printf("Saving OpenSSH public key to %s ...\n", public_file_path); 34 | 35 | fd = open(public_file_path, O_WRONLY | O_CREAT | O_EXCL, 0600); 36 | free(public_file_path); 37 | 38 | if (fd == -1) 39 | { 40 | fprintf(stderr, "Error: Unable to write public key (%s)\n", strerror(errno)); 41 | return false; 42 | } 43 | 44 | struct buffer *body = buffer_new(51); 45 | struct buffer_writer *body_writer = buffer_writer_new(body); 46 | bool ok = true; 47 | 48 | ok &= buffer_writer_write_uint32(body_writer, 11); 49 | ok &= buffer_writer_write_value(body_writer, "ssh-ed25519", 11); 50 | ok &= buffer_writer_write_uint32(body_writer, 32); 51 | ok &= buffer_writer_write_value(body_writer, public, 32); 52 | buffer_writer_free(body_writer); 53 | 54 | struct buffer *body_base64 = NULL; 55 | ok &= buffer_base64_encode(body, &body_base64); 56 | buffer_free(body); 57 | 58 | struct buffer * final_buf = buffer_new(12 + body_base64->size + 1 + username_length + 1); 59 | struct buffer_writer * final_writer = buffer_writer_new(final_buf); 60 | 61 | ok &= buffer_writer_write_asciiz(final_writer, "ssh-ed25519 "); 62 | ok &= buffer_writer_write_value(final_writer, body_base64->data, body_base64->size); 63 | buffer_free(body_base64); 64 | 65 | ok &= buffer_writer_write_asciiz(final_writer, " "); 66 | ok &= buffer_writer_write_value(final_writer, username, username_length); 67 | ok &= buffer_writer_write_asciiz(final_writer, "\n"); 68 | buffer_writer_free(final_writer); 69 | 70 | if(!ok) 71 | { 72 | fprintf(stderr, "Error: Not enough memory when generating public key\n"); 73 | } 74 | else 75 | { 76 | const char * final_str = buffer_string(final_buf); 77 | if(write(fd, final_str, strlen(final_str)) != (ssize_t) strlen(final_str)) 78 | { 79 | fprintf(stderr, "Error: Unable to write public key file (%s)\n", strerror(errno)); 80 | ok = false; 81 | } 82 | 83 | } 84 | 85 | buffer_free(final_buf); 86 | 87 | if (close(fd)) 88 | { 89 | fprintf(stderr, "Error: Unable to close public key file (%s)\n", strerror(errno)); 90 | ok = false; 91 | } 92 | 93 | return ok; 94 | } 95 | 96 | static bool openssh_write_secret(const char *output_directory, const char *username, size_t username_length, unsigned char *public, unsigned char *secret) 97 | { 98 | char *secret_file_path = NULL; 99 | int fd = 0; 100 | 101 | if (output_directory != NULL) 102 | { 103 | size_t secret_file_path_len = strlen(output_directory) + 12; 104 | secret_file_path = malloc(secret_file_path_len); 105 | snprintf(secret_file_path, secret_file_path_len, "%s/id_ed25519", output_directory); 106 | } 107 | else 108 | secret_file_path = strdup("id_ed25519"); 109 | 110 | printf("Saving OpenSSH secret key to %s ...\n", secret_file_path); 111 | 112 | fd = open(secret_file_path, O_WRONLY | O_CREAT | O_EXCL, 0600); 113 | free(secret_file_path); 114 | 115 | if (fd == -1) 116 | { 117 | fprintf(stderr, "Error: Unable to write secret key (%s)\n", strerror(errno)); 118 | return false; 119 | } 120 | 121 | uint32_t private_length = (4 + 4) + (4 + 11 + 4 + 32) + (4 + 64) + (4 + username_length); 122 | uint32_t padding = private_length % 8; 123 | 124 | if (padding != 0) 125 | padding = 8 - padding; 126 | 127 | struct buffer *body = buffer_new(15 + (4 + 4) + (4 + 4) + 4 + 4 + 4 + (4 + 11 + 4 + 32) + 4 + private_length + padding); 128 | struct buffer *body_base64 = NULL; 129 | struct buffer_writer *body_writer = buffer_writer_new(body); 130 | bool ok = true; 131 | 132 | // Header. 133 | ok &= buffer_writer_write_value(body_writer, "openssh-key-v1\x00", 15); 134 | 135 | // Cipher. 136 | ok &= buffer_writer_write_uint32(body_writer, 4); 137 | ok &= buffer_writer_write_value(body_writer, "none", 4); 138 | 139 | // KDF. 140 | ok &= buffer_writer_write_uint32(body_writer, 4); 141 | ok &= buffer_writer_write_value(body_writer, "none", 4); 142 | 143 | // KDF Options. 144 | ok &= buffer_writer_write_uint32(body_writer, 0); 145 | 146 | // Number of Public Keys 147 | ok &= buffer_writer_write_uint32(body_writer, 1); 148 | 149 | // Public Keys Length. 150 | ok &= buffer_writer_write_uint32(body_writer, 51); 151 | 152 | // Public Key. 153 | ok &= buffer_writer_write_uint32(body_writer, 11); 154 | ok &= buffer_writer_write_value(body_writer, "ssh-ed25519", 11); 155 | ok &= buffer_writer_write_uint32(body_writer, 32); 156 | ok &= buffer_writer_write_value(body_writer, public, 32); 157 | 158 | // Private key section 159 | 160 | // {checkint} is a random integer used to identify a correctly decrypted 161 | // private key in cases where the private key is encrypted. ours are not. 162 | const uint32_t checkint = 0x12345678; 163 | 164 | ok &= buffer_writer_write_uint32(body_writer, private_length + padding); 165 | 166 | ok &= buffer_writer_write_uint32(body_writer, checkint); 167 | ok &= buffer_writer_write_uint32(body_writer, checkint); 168 | 169 | ok &= buffer_writer_write_uint32(body_writer, 11); 170 | ok &= buffer_writer_write_value(body_writer, "ssh-ed25519", 11); 171 | ok &= buffer_writer_write_uint32(body_writer, 32); 172 | ok &= buffer_writer_write_value(body_writer, public, 32); 173 | 174 | ok &= buffer_writer_write_uint32(body_writer, 64); 175 | ok &= buffer_writer_write_value(body_writer, secret, 64); 176 | 177 | ok &= buffer_writer_write_uint32(body_writer, username_length); 178 | ok &= buffer_writer_write_value(body_writer, username, username_length); 179 | 180 | uint8_t pad = 0; 181 | while (padding--) 182 | ok &= buffer_writer_write_uint8(body_writer, ++pad & 0xff); 183 | 184 | buffer_writer_free(body_writer); 185 | 186 | // BASE64 encode the buffer. 187 | ok &= buffer_base64_encode(body, &body_base64); 188 | 189 | struct buffer * fd_buf = buffer_new( 190 | 36 // "BEGIN OPENSSH PRIVATE KEY..." 191 | + body_base64->size 192 | + (body_base64->size / 70) + (body_base64->size % 70) // newlines 193 | + 34 // "END OPENSSH PRIVATE KEY..." 194 | ); 195 | struct buffer_writer * fd_writer = buffer_writer_new(fd_buf); 196 | 197 | ok &= buffer_writer_write_asciiz(fd_writer, "-----BEGIN OPENSSH PRIVATE KEY-----\n"); 198 | ok &= buffer_writer_write_asciiz_with_linewrapping(fd_writer, (char *) body_base64->data, 70); 199 | ok &= buffer_writer_write_asciiz(fd_writer, "\n"); 200 | ok &= buffer_writer_write_asciiz(fd_writer, "-----END OPENSSH PRIVATE KEY-----\n"); 201 | 202 | buffer_writer_free(fd_writer); 203 | 204 | if(!ok) 205 | { 206 | fprintf(stderr, "Error: Not enough memory to build secret key.\n"); 207 | return false; 208 | } 209 | 210 | const char * fd_str = buffer_string(fd_buf); 211 | if(write(fd, fd_str, strlen(fd_str)) != (ssize_t) strlen(fd_str)) 212 | { 213 | fprintf(stderr, "Error: Unable to write private key file (%s)\n", strerror(errno)); 214 | return false; 215 | } 216 | 217 | close(fd); 218 | 219 | buffer_free(body); 220 | buffer_free(body_base64); 221 | buffer_free(fd_buf); 222 | 223 | return true; 224 | } 225 | 226 | bool openssh_write(const char *output_directory, const char *username, size_t username_length, unsigned char *secret, unsigned char *public) 227 | { 228 | if (! openssh_write_secret(output_directory, username, username_length, public, secret)) 229 | return false; 230 | 231 | if (! openssh_write_public(output_directory, username, username_length, public)) 232 | return false; 233 | 234 | return true; 235 | } 236 | -------------------------------------------------------------------------------- /src/openssh.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #ifndef GUARD_OPENSSH_H 6 | #define GUARD_OPENSSH_H 1 7 | 8 | #include 9 | 10 | bool openssh_write(const char *output_directory, const char *username, size_t username_length, unsigned char *secret, unsigned char *public); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/profile.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "profile.h" 11 | 12 | #define PROFILE_2015_NAME "2015v1" 13 | #define PROFILE_2015_USERNAME_SALT "2015v1" 14 | #define PROFILE_2015_OPSLIMIT 33554432ULL 15 | #define PROFILE_2015_MEMLIMIT 1073741824ULL 16 | #define PROFILE_2015_OPENSSH_SALT "" 17 | #define PROFILE_2015_OPENPGP_SALT "passphrase-identity-2015v1.gpg" 18 | #define PROFILE_2015_MATERIAL_LENGTH crypto_sign_ed25519_SEEDBYTES 19 | 20 | #define PROFILE_2017_NAME "2017" 21 | #define PROFILE_2017_USERNAME_SALT "passphrase-identity-2017.salt" 22 | #define PROFILE_2017_OPSLIMIT 120304050ULL 23 | #define PROFILE_2017_MEMLIMIT 1073741824ULL 24 | #define PROFILE_2017_OPENSSH_SALT "passphrase-identity-2017.ssh" 25 | #define PROFILE_2017_OPENPGP_SALT "passphrase-identity-2017.gpg" 26 | #define PROFILE_2017_MATERIAL_LENGTH 64 27 | 28 | bool is_valid_profile_name(const char *name) 29 | { 30 | if (name == NULL) 31 | { 32 | return false; 33 | } 34 | 35 | bool ok = (0 == strcmp(name, PROFILE_2015_NAME)); 36 | ok |= (0 == strcmp(name, PROFILE_2017_NAME)); 37 | 38 | return ok; 39 | } 40 | 41 | static unsigned char * generate_material(struct profile_t * profile) 42 | { 43 | assert(crypto_pwhash_scryptsalsa208sha256_SALTBYTES >= crypto_generichash_BYTES_MIN); 44 | 45 | bool success = false; 46 | 47 | unsigned char * material = sodium_malloc(profile->material_length); 48 | if(NULL == material) 49 | return NULL; 50 | 51 | unsigned char * salt = sodium_malloc(crypto_pwhash_scryptsalsa208sha256_SALTBYTES); 52 | if(NULL == salt) 53 | goto generate_material_free_material; 54 | 55 | // Compute the salt from the given username and profile version. 56 | if(0 != crypto_generichash(salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES, (const unsigned char *) profile->username, strlen(profile->username), (const unsigned char *) profile->username_salt, strlen(profile->username_salt))) 57 | goto generate_material_free_salt; 58 | 59 | if(0 == crypto_pwhash_scryptsalsa208sha256(material, profile->material_length, profile->passphrase, strlen(profile->passphrase), salt, profile->opslimit, profile->memlimit)) 60 | success = true; 61 | 62 | generate_material_free_salt: 63 | sodium_free(salt); 64 | 65 | generate_material_free_material: 66 | if( !success ) 67 | sodium_free(material); 68 | 69 | return material; 70 | } 71 | 72 | bool generate_openssh_keypair(struct profile_t * profile) 73 | { 74 | bool success = false; 75 | 76 | if(NULL == profile || NULL == profile->material || profile->material_length < 16 || NULL == profile->openssh_salt) 77 | return false; 78 | 79 | unsigned char seed[crypto_sign_ed25519_SEEDBYTES]; 80 | sodium_memzero(seed, sizeof(seed)); 81 | 82 | // To maintain backwards compatibility with "2015v1" profile: 83 | if(0 == strcmp(profile->profile_name, PROFILE_2015_NAME) && crypto_sign_ed25519_SEEDBYTES == profile->material_length) 84 | { 85 | memcpy(seed, profile->material, crypto_sign_ed25519_SEEDBYTES); 86 | } 87 | else 88 | { 89 | if(0 != crypto_generichash(seed, sizeof(seed), (const unsigned char *) profile->openssh_salt, strlen(profile->openssh_salt), profile->material, profile->material_length)) 90 | return false; 91 | } 92 | 93 | if(0 == crypto_sign_ed25519_seed_keypair((unsigned char *) &(profile->openssh_public), (unsigned char *) &(profile->openssh_secret), seed)) 94 | success = true; 95 | 96 | sodium_memzero(seed, sizeof(seed)); 97 | 98 | return success; 99 | } 100 | 101 | bool generate_openpgp_keypair(struct profile_t * profile) 102 | { 103 | bool success = false; 104 | 105 | if(NULL == profile || NULL == profile->material || profile->material_length < 16 || NULL == profile->openpgp_salt) 106 | return false; 107 | 108 | if(0 == strcmp(profile->profile_name, PROFILE_2015_NAME)) 109 | { 110 | // 2015 didn't have "material" originally, so we need to do a new round of scrypt for non-openssh keys 111 | unsigned char * salt = sodium_malloc(crypto_pwhash_scryptsalsa208sha256_SALTBYTES); 112 | bool salt_ok = false; 113 | if(NULL == salt) return false; 114 | 115 | if(0 != crypto_generichash(salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES, (const unsigned char *) profile->username, strlen(profile->username), profile->material, profile->material_length)) 116 | goto openpgp_free_salt; 117 | 118 | if(0 == crypto_pwhash_scryptsalsa208sha256(profile->openpgp_secret, sizeof(profile->openpgp_secret), profile->passphrase, strlen(profile->passphrase), salt, profile->opslimit, profile->memlimit)) 119 | salt_ok = true; 120 | 121 | openpgp_free_salt: 122 | sodium_free(salt); 123 | 124 | if(!salt_ok) 125 | goto error; 126 | } 127 | else 128 | { 129 | if(0 != crypto_generichash(profile->openpgp_secret, sizeof(profile->openpgp_secret), (const unsigned char *) profile->openpgp_salt, strlen(profile->openpgp_salt), profile->material, profile->material_length)) 130 | goto error; 131 | } 132 | 133 | unsigned char * secret = sodium_malloc(crypto_sign_ed25519_SECRETKEYBYTES); 134 | if(NULL == secret) goto error; 135 | 136 | if(0 == crypto_sign_ed25519_seed_keypair((unsigned char *) &(profile->openpgp_public), secret, profile->openpgp_secret)) 137 | success = true; 138 | 139 | sodium_free(secret); 140 | 141 | error: 142 | 143 | return success; 144 | } 145 | 146 | profile_t * generate_profile(const char *profile_name, const char *username, const char *passphrase) 147 | { 148 | 149 | if(NULL == profile_name || NULL == username || NULL == passphrase || 0 == strlen(profile_name)) 150 | return NULL; 151 | 152 | struct profile_t * profile = sodium_malloc(sizeof(profile_t)); 153 | if (NULL == profile) 154 | return NULL; 155 | 156 | sodium_memzero(profile, sizeof(profile_t)); 157 | 158 | strncpy((char *) profile->username, username, sizeof(profile->username)); 159 | strncpy((char *) profile->passphrase, passphrase, sizeof(profile->passphrase)); 160 | 161 | if (0 == strcmp(profile_name, PROFILE_2015_NAME)) 162 | { 163 | profile->profile_name = PROFILE_2015_NAME; 164 | profile->username_salt = PROFILE_2015_USERNAME_SALT; 165 | profile->material_length = PROFILE_2015_MATERIAL_LENGTH; 166 | profile->opslimit = PROFILE_2015_OPSLIMIT; 167 | profile->memlimit = PROFILE_2015_MEMLIMIT; 168 | profile->openssh_salt = PROFILE_2015_OPENSSH_SALT; 169 | profile->openpgp_salt = PROFILE_2015_OPENPGP_SALT; 170 | } 171 | 172 | if (0 == strcmp(profile_name, PROFILE_2017_NAME)) 173 | { 174 | profile->profile_name = PROFILE_2017_NAME; 175 | profile->username_salt = PROFILE_2017_USERNAME_SALT; 176 | profile->material_length = PROFILE_2017_MATERIAL_LENGTH; 177 | profile->opslimit = PROFILE_2017_OPSLIMIT; 178 | profile->memlimit = PROFILE_2017_MEMLIMIT; 179 | profile->openssh_salt = PROFILE_2017_OPENSSH_SALT; 180 | profile->openpgp_salt = PROFILE_2017_OPENPGP_SALT; 181 | } 182 | 183 | profile->material = generate_material(profile); 184 | 185 | if (NULL == profile->material) 186 | { 187 | sodium_free(profile); 188 | profile = NULL; 189 | } 190 | 191 | return profile; 192 | } 193 | 194 | bool free_profile_t(struct profile_t * profile) 195 | { 196 | bool ok = false; 197 | 198 | sodium_free(profile->material); 199 | 200 | sodium_memzero(profile, sizeof(profile_t)); 201 | 202 | sodium_free(profile); 203 | 204 | return ok; 205 | } 206 | -------------------------------------------------------------------------------- /src/profile.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #ifndef GUARD_PROFILE_H 6 | #define GUARD_PROFILE_H 1 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #define DEFAULT_PROFILE "2017" 13 | 14 | typedef struct profile_t 15 | { 16 | // Inline the integers to avoid having to deal with pointer lifetime: 17 | size_t material_length; 18 | unsigned long long opslimit; 19 | unsigned long long memlimit; 20 | 21 | // These are always set to global pointers to PROFILE_20##_* constants: 22 | char * profile_name; 23 | char * username_salt; 24 | char * openssh_salt; 25 | char * openpgp_salt; 26 | 27 | unsigned char * material; 28 | 29 | // Inline these to keep them in the sodium_malloc() buffer: 30 | char passphrase[256]; 31 | char username[90]; 32 | 33 | char openssh_secret[crypto_sign_ed25519_SECRETKEYBYTES]; 34 | // Note that PGP stores the seed ("d") and computes the actual private key 35 | // for every signature. Internally it just stores "d". 36 | unsigned char openpgp_secret[crypto_sign_ed25519_SEEDBYTES]; 37 | 38 | char openssh_public[crypto_sign_ed25519_PUBLICKEYBYTES]; 39 | unsigned char openpgp_public[crypto_sign_ed25519_PUBLICKEYBYTES]; 40 | } profile_t; 41 | 42 | bool is_valid_profile_name(const char *profile_name); 43 | 44 | struct profile_t * generate_profile(const char *profile_name, const char *username, const char *passphrase); 45 | 46 | bool generate_openssh_keypair(struct profile_t * profile); 47 | bool generate_openpgp_keypair(struct profile_t * profile); 48 | 49 | bool free_profile_t(struct profile_t * profile); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/readpassphrase.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: readpassphrase.c,v 1.22 2010/01/13 10:20:54 dtucker Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 2000-2002, 2007 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | * Sponsored in part by the Defense Advanced Research Projects 19 | * Agency (DARPA) and Air Force Research Laboratory, Air Force 20 | * Materiel Command, USAF, under agreement number F39502-99-1-0512. 21 | */ 22 | 23 | /* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */ 24 | 25 | #ifndef HAVE_READPASSPHRASE 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #ifdef TCSASOFT 37 | # define _T_FLUSH (TCSAFLUSH|TCSASOFT) 38 | #else 39 | # define _T_FLUSH (TCSAFLUSH) 40 | #endif 41 | 42 | #ifndef _PATH_TTY 43 | # define _PATH_TTY "/dev/tty" 44 | #endif 45 | 46 | /* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */ 47 | #if !defined(_POSIX_VDISABLE) && defined(VDISABLE) 48 | # define _POSIX_VDISABLE VDISABLE 49 | #endif 50 | 51 | #ifndef _NSIG 52 | # ifdef NSIG 53 | # define _NSIG NSIG 54 | # else 55 | # define _NSIG 128 56 | # endif 57 | #endif 58 | 59 | static volatile sig_atomic_t signo[_NSIG]; 60 | 61 | static void handler(int); 62 | 63 | char * 64 | readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) 65 | { 66 | ssize_t nr; 67 | int input, output, save_errno, i, need_restart; 68 | char ch, *p, *end; 69 | struct termios term, oterm; 70 | struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; 71 | struct sigaction savetstp, savettin, savettou, savepipe; 72 | 73 | /* I suppose we could alloc on demand in this case (XXX). */ 74 | if (bufsiz == 0) { 75 | errno = EINVAL; 76 | return(NULL); 77 | } 78 | 79 | restart: 80 | for (i = 0; i < _NSIG; i++) 81 | signo[i] = 0; 82 | nr = -1; 83 | save_errno = 0; 84 | need_restart = 0; 85 | /* 86 | * Read and write to /dev/tty if available. If not, read from 87 | * stdin and write to stderr unless a tty is required. 88 | */ 89 | if ((flags & RPP_STDIN) || 90 | (input = output = open(_PATH_TTY, O_RDWR)) == -1) { 91 | if (flags & RPP_REQUIRE_TTY) { 92 | errno = ENOTTY; 93 | return(NULL); 94 | } 95 | input = STDIN_FILENO; 96 | output = STDERR_FILENO; 97 | } 98 | 99 | /* 100 | * Catch signals that would otherwise cause the user to end 101 | * up with echo turned off in the shell. Don't worry about 102 | * things like SIGXCPU and SIGVTALRM for now. 103 | */ 104 | sigemptyset(&sa.sa_mask); 105 | sa.sa_flags = 0; /* don't restart system calls */ 106 | sa.sa_handler = handler; 107 | (void)sigaction(SIGALRM, &sa, &savealrm); 108 | (void)sigaction(SIGHUP, &sa, &savehup); 109 | (void)sigaction(SIGINT, &sa, &saveint); 110 | (void)sigaction(SIGPIPE, &sa, &savepipe); 111 | (void)sigaction(SIGQUIT, &sa, &savequit); 112 | (void)sigaction(SIGTERM, &sa, &saveterm); 113 | (void)sigaction(SIGTSTP, &sa, &savetstp); 114 | (void)sigaction(SIGTTIN, &sa, &savettin); 115 | (void)sigaction(SIGTTOU, &sa, &savettou); 116 | 117 | /* Turn off echo if possible. */ 118 | if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) { 119 | memcpy(&term, &oterm, sizeof(term)); 120 | if (!(flags & RPP_ECHO_ON)) 121 | term.c_lflag &= ~(ECHO | ECHONL); 122 | #ifdef VSTATUS 123 | if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) 124 | term.c_cc[VSTATUS] = _POSIX_VDISABLE; 125 | #endif 126 | (void)tcsetattr(input, _T_FLUSH, &term); 127 | } else { 128 | memset(&term, 0, sizeof(term)); 129 | term.c_lflag |= ECHO; 130 | memset(&oterm, 0, sizeof(oterm)); 131 | oterm.c_lflag |= ECHO; 132 | } 133 | 134 | /* No I/O if we are already backgrounded. */ 135 | if (signo[SIGTTOU] != 1 && signo[SIGTTIN] != 1) { 136 | # if __GNUC__ 137 | # pragma GCC diagnostic push 138 | # pragma GCC diagnostic ignored "-Wunused-result" 139 | # endif 140 | if (!(flags & RPP_STDIN)) 141 | (void)write(output, prompt, strlen(prompt)); 142 | # if __GNUC__ 143 | # pragma GCC diagnostic pop 144 | # endif 145 | end = buf + bufsiz - 1; 146 | p = buf; 147 | while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') { 148 | if (p < end) { 149 | if ((flags & RPP_SEVENBIT)) 150 | ch &= 0x7f; 151 | if (isalpha(ch)) { 152 | if ((flags & RPP_FORCELOWER)) 153 | ch = (char)tolower(ch); 154 | if ((flags & RPP_FORCEUPPER)) 155 | ch = (char)toupper(ch); 156 | } 157 | *p++ = ch; 158 | } 159 | } 160 | *p = '\0'; 161 | save_errno = errno; 162 | # if __GNUC__ 163 | # pragma GCC diagnostic push 164 | # pragma GCC diagnostic ignored "-Wunused-result" 165 | # endif 166 | if (!(term.c_lflag & ECHO)) 167 | (void)write(output, "\n", 1); 168 | # if __GNUC__ 169 | # pragma GCC diagnostic pop 170 | # endif 171 | } 172 | 173 | /* Restore old terminal settings and signals. */ 174 | if (memcmp(&term, &oterm, sizeof(term)) != 0) { 175 | while (tcsetattr(input, _T_FLUSH, &oterm) == -1 && 176 | errno == EINTR) 177 | continue; 178 | } 179 | (void)sigaction(SIGALRM, &savealrm, NULL); 180 | (void)sigaction(SIGHUP, &savehup, NULL); 181 | (void)sigaction(SIGINT, &saveint, NULL); 182 | (void)sigaction(SIGQUIT, &savequit, NULL); 183 | (void)sigaction(SIGPIPE, &savepipe, NULL); 184 | (void)sigaction(SIGTERM, &saveterm, NULL); 185 | (void)sigaction(SIGTSTP, &savetstp, NULL); 186 | (void)sigaction(SIGTTIN, &savettin, NULL); 187 | (void)sigaction(SIGTTOU, &savettou, NULL); 188 | if (input != STDIN_FILENO) 189 | (void)close(input); 190 | 191 | /* 192 | * If we were interrupted by a signal, resend it to ourselves 193 | * now that we have restored the signal handlers. 194 | */ 195 | for (i = 0; i < _NSIG; i++) { 196 | if (signo[i]) { 197 | kill(getpid(), i); 198 | switch (i) { 199 | case SIGTSTP: 200 | case SIGTTIN: 201 | case SIGTTOU: 202 | need_restart = 1; 203 | default: 204 | ; /* Don't restart. */ 205 | } 206 | } 207 | } 208 | if (need_restart) 209 | goto restart; 210 | 211 | if (save_errno) 212 | errno = save_errno; 213 | return(nr == -1 ? NULL : buf); 214 | } 215 | 216 | #if 0 217 | char * 218 | getpass(const char *prompt) 219 | { 220 | static char buf[_PASSWORD_LEN + 1]; 221 | 222 | return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF)); 223 | } 224 | #endif 225 | 226 | static void handler(int s) 227 | { 228 | 229 | signo[s] = 1; 230 | } 231 | #endif /* HAVE_READPASSPHRASE */ 232 | -------------------------------------------------------------------------------- /src/readpassphrase.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: readpassphrase.h,v 1.5 2003/06/17 21:56:23 millert Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 2000, 2002 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | * Sponsored in part by the Defense Advanced Research Projects 19 | * Agency (DARPA) and Air Force Research Laboratory, Air Force 20 | * Materiel Command, USAF, under agreement number F39502-99-1-0512. 21 | */ 22 | 23 | /* OPENBSD ORIGINAL: include/readpassphrase.h */ 24 | 25 | #ifndef _READPASSPHRASE_H_ 26 | #define _READPASSPHRASE_H_ 27 | 28 | #ifndef HAVE_READPASSPHRASE 29 | #include 30 | 31 | #define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */ 32 | #define RPP_ECHO_ON 0x01 /* Leave echo on. */ 33 | #define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */ 34 | #define RPP_FORCELOWER 0x04 /* Force input to lower case. */ 35 | #define RPP_FORCEUPPER 0x08 /* Force input to upper case. */ 36 | #define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */ 37 | #define RPP_STDIN 0x20 /* Read from stdin, not /dev/tty */ 38 | 39 | char * readpassphrase(const char *, char *, size_t, int); 40 | 41 | #endif /* HAVE_READPASSPHRASE */ 42 | 43 | #endif /* !_READPASSPHRASE_H_ */ 44 | -------------------------------------------------------------------------------- /src/sha-private.h: -------------------------------------------------------------------------------- 1 | /************************ sha.private.h ************************/ 2 | /***************** See RFC 6234 for details. *******************/ 3 | #ifndef _SHA_PRIVATE__H 4 | #define _SHA_PRIVATE__H 5 | /* 6 | * These definitions are defined in FIPS 180-3, section 4.1. 7 | * Ch() and Maj() are defined identically in sections 4.1.1, 8 | * 4.1.2, and 4.1.3. 9 | * 10 | * The definitions used in FIPS 180-3 are as follows: 11 | */ 12 | 13 | #ifndef USE_MODIFIED_MACROS 14 | #define SHA_Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) 15 | #define SHA_Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) 16 | #else /* USE_MODIFIED_MACROS */ 17 | /* 18 | * The following definitions are equivalent and potentially faster. 19 | */ 20 | 21 | #define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z)) 22 | #define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) 23 | 24 | #endif /* USE_MODIFIED_MACROS */ 25 | 26 | #define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z)) 27 | 28 | #endif /* _SHA_PRIVATE__H */ 29 | -------------------------------------------------------------------------------- /src/sha.h: -------------------------------------------------------------------------------- 1 | /**************************** sha.h ****************************/ 2 | /***************** See RFC 6234 for details. *******************/ 3 | /* 4 | Copyright (c) 2011 IETF Trust and the persons identified as 5 | authors of the code. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or 8 | without modification, are permitted provided that the following 9 | conditions are met: 10 | 11 | - Redistributions of source code must retain the above 12 | copyright notice, this list of conditions and 13 | the following disclaimer. 14 | 15 | - Redistributions in binary form must reproduce the above 16 | copyright notice, this list of conditions and the following 17 | disclaimer in the documentation and/or other materials provided 18 | with the distribution. 19 | 20 | - Neither the name of Internet Society, IETF or IETF Trust, nor 21 | the names of specific contributors, may be used to endorse or 22 | promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 26 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 27 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 28 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 30 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 32 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 36 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 37 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | */ 39 | #ifndef _SHA_H_ 40 | #define _SHA_H_ 41 | 42 | /* 43 | * Description: 44 | * This file implements the Secure Hash Algorithms 45 | * as defined in the U.S. National Institute of Standards 46 | * and Technology Federal Information Processing Standards 47 | * Publication (FIPS PUB) 180-3 published in October 2008 48 | * and formerly defined in its predecessors, FIPS PUB 180-1 49 | * and FIP PUB 180-2. 50 | * 51 | * A combined document showing all algorithms is available at 52 | * http://csrc.nist.gov/publications/fips/ 53 | * fips180-3/fips180-3_final.pdf 54 | * 55 | * The five hashes are defined in these sizes: 56 | * SHA-1 20 byte / 160 bit 57 | * SHA-224 28 byte / 224 bit 58 | * SHA-256 32 byte / 256 bit 59 | * SHA-384 48 byte / 384 bit 60 | * SHA-512 64 byte / 512 bit 61 | * 62 | * Compilation Note: 63 | * These files may be compiled with two options: 64 | * USE_32BIT_ONLY - use 32-bit arithmetic only, for systems 65 | * without 64-bit integers 66 | * 67 | * USE_MODIFIED_MACROS - use alternate form of the SHA_Ch() 68 | * and SHA_Maj() macros that are equivalent 69 | * and potentially faster on many systems 70 | * 71 | */ 72 | 73 | #include 74 | /* 75 | * If you do not have the ISO standard stdint.h header file, then you 76 | * must typedef the following: 77 | * name meaning 78 | * uint64_t unsigned 64-bit integer 79 | * uint32_t unsigned 32-bit integer 80 | * uint8_t unsigned 8-bit integer (i.e., unsigned char) 81 | * int_least16_t integer of >= 16 bits 82 | * 83 | * See stdint-example.h 84 | */ 85 | 86 | #ifndef _SHA_enum_ 87 | #define _SHA_enum_ 88 | /* 89 | * All SHA functions return one of these values. 90 | */ 91 | enum { 92 | shaSuccess = 0, 93 | shaNull, /* Null pointer parameter */ 94 | shaInputTooLong, /* input data too long */ 95 | shaStateError, /* called Input after FinalBits or Result */ 96 | shaBadParam /* passed a bad parameter */ 97 | }; 98 | #endif /* _SHA_enum_ */ 99 | 100 | /* 101 | * These constants hold size information for each of the SHA 102 | * hashing operations 103 | */ 104 | enum { 105 | SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64, 106 | SHA256_Message_Block_Size = 64, SHA384_Message_Block_Size = 128, 107 | SHA512_Message_Block_Size = 128, 108 | USHA_Max_Message_Block_Size = SHA512_Message_Block_Size, 109 | 110 | SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32, 111 | SHA384HashSize = 48, SHA512HashSize = 64, 112 | USHAMaxHashSize = SHA512HashSize, 113 | 114 | SHA1HashSizeBits = 160, SHA224HashSizeBits = 224, 115 | SHA256HashSizeBits = 256, SHA384HashSizeBits = 384, 116 | SHA512HashSizeBits = 512, USHAMaxHashSizeBits = SHA512HashSizeBits 117 | }; 118 | 119 | /* 120 | * These constants are used in the USHA (Unified SHA) functions. 121 | */ 122 | typedef enum SHAversion { 123 | SHA1, SHA224, SHA256, SHA384, SHA512 124 | } SHAversion; 125 | 126 | /* 127 | * This structure will hold context information for the SHA-1 128 | * hashing operation. 129 | */ 130 | typedef struct SHA1Context { 131 | uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ 132 | 133 | uint32_t Length_High; /* Message length in bits */ 134 | uint32_t Length_Low; /* Message length in bits */ 135 | 136 | int_least16_t Message_Block_Index; /* Message_Block array index */ 137 | /* 512-bit message blocks */ 138 | uint8_t Message_Block[SHA1_Message_Block_Size]; 139 | 140 | int Computed; /* Is the hash computed? */ 141 | int Corrupted; /* Cumulative corruption code */ 142 | } SHA1Context; 143 | 144 | /* 145 | * This structure will hold context information for the SHA-256 146 | * hashing operation. 147 | */ 148 | typedef struct SHA256Context { 149 | uint32_t Intermediate_Hash[SHA256HashSize/4]; /* Message Digest */ 150 | 151 | uint32_t Length_High; /* Message length in bits */ 152 | uint32_t Length_Low; /* Message length in bits */ 153 | 154 | int_least16_t Message_Block_Index; /* Message_Block array index */ 155 | /* 512-bit message blocks */ 156 | uint8_t Message_Block[SHA256_Message_Block_Size]; 157 | 158 | int Computed; /* Is the hash computed? */ 159 | int Corrupted; /* Cumulative corruption code */ 160 | } SHA256Context; 161 | 162 | /* 163 | * This structure will hold context information for the SHA-512 164 | * hashing operation. 165 | */ 166 | typedef struct SHA512Context { 167 | #ifdef USE_32BIT_ONLY 168 | uint32_t Intermediate_Hash[SHA512HashSize/4]; /* Message Digest */ 169 | uint32_t Length[4]; /* Message length in bits */ 170 | #else /* !USE_32BIT_ONLY */ 171 | uint64_t Intermediate_Hash[SHA512HashSize/8]; /* Message Digest */ 172 | uint64_t Length_High, Length_Low; /* Message length in bits */ 173 | #endif /* USE_32BIT_ONLY */ 174 | 175 | int_least16_t Message_Block_Index; /* Message_Block array index */ 176 | /* 1024-bit message blocks */ 177 | uint8_t Message_Block[SHA512_Message_Block_Size]; 178 | 179 | int Computed; /* Is the hash computed?*/ 180 | int Corrupted; /* Cumulative corruption code */ 181 | } SHA512Context; 182 | 183 | /* 184 | * This structure will hold context information for the SHA-224 185 | * hashing operation. It uses the SHA-256 structure for computation. 186 | */ 187 | typedef struct SHA256Context SHA224Context; 188 | 189 | /* 190 | * This structure will hold context information for the SHA-384 191 | * hashing operation. It uses the SHA-512 structure for computation. 192 | */ 193 | typedef struct SHA512Context SHA384Context; 194 | 195 | /* 196 | * This structure holds context information for all SHA 197 | * hashing operations. 198 | */ 199 | typedef struct USHAContext { 200 | int whichSha; /* which SHA is being used */ 201 | union { 202 | SHA1Context sha1Context; 203 | SHA224Context sha224Context; SHA256Context sha256Context; 204 | SHA384Context sha384Context; SHA512Context sha512Context; 205 | } ctx; 206 | } USHAContext; 207 | 208 | /* 209 | * This structure will hold context information for the HMAC 210 | * keyed-hashing operation. 211 | */ 212 | typedef struct HMACContext { 213 | int whichSha; /* which SHA is being used */ 214 | int hashSize; /* hash size of SHA being used */ 215 | int blockSize; /* block size of SHA being used */ 216 | USHAContext shaContext; /* SHA context */ 217 | unsigned char k_opad[USHA_Max_Message_Block_Size]; 218 | /* outer padding - key XORd with opad */ 219 | int Computed; /* Is the MAC computed? */ 220 | int Corrupted; /* Cumulative corruption code */ 221 | 222 | } HMACContext; 223 | 224 | /* 225 | * This structure will hold context information for the HKDF 226 | * extract-and-expand Key Derivation Functions. 227 | */ 228 | typedef struct HKDFContext { 229 | int whichSha; /* which SHA is being used */ 230 | HMACContext hmacContext; 231 | int hashSize; /* hash size of SHA being used */ 232 | unsigned char prk[USHAMaxHashSize]; 233 | /* pseudo-random key - output of hkdfInput */ 234 | int Computed; /* Is the key material computed? */ 235 | int Corrupted; /* Cumulative corruption code */ 236 | } HKDFContext; 237 | 238 | /* 239 | * Function Prototypes 240 | */ 241 | 242 | /* SHA-1 */ 243 | extern int SHA1Reset(SHA1Context *); 244 | extern int SHA1Input(SHA1Context *, const uint8_t *bytes, 245 | unsigned int bytecount); 246 | extern int SHA1FinalBits(SHA1Context *, uint8_t bits, 247 | unsigned int bit_count); 248 | extern int SHA1Result(SHA1Context *, 249 | uint8_t Message_Digest[SHA1HashSize]); 250 | 251 | /* SHA-224 */ 252 | extern int SHA224Reset(SHA224Context *); 253 | extern int SHA224Input(SHA224Context *, const uint8_t *bytes, 254 | unsigned int bytecount); 255 | extern int SHA224FinalBits(SHA224Context *, uint8_t bits, 256 | unsigned int bit_count); 257 | extern int SHA224Result(SHA224Context *, 258 | uint8_t Message_Digest[SHA224HashSize]); 259 | 260 | /* SHA-256 */ 261 | extern int SHA256Reset(SHA256Context *); 262 | extern int SHA256Input(SHA256Context *, const uint8_t *bytes, 263 | unsigned int bytecount); 264 | extern int SHA256FinalBits(SHA256Context *, uint8_t bits, 265 | unsigned int bit_count); 266 | extern int SHA256Result(SHA256Context *, 267 | uint8_t Message_Digest[SHA256HashSize]); 268 | 269 | /* SHA-384 */ 270 | extern int SHA384Reset(SHA384Context *); 271 | extern int SHA384Input(SHA384Context *, const uint8_t *bytes, 272 | unsigned int bytecount); 273 | extern int SHA384FinalBits(SHA384Context *, uint8_t bits, 274 | unsigned int bit_count); 275 | extern int SHA384Result(SHA384Context *, 276 | uint8_t Message_Digest[SHA384HashSize]); 277 | 278 | /* SHA-512 */ 279 | extern int SHA512Reset(SHA512Context *); 280 | extern int SHA512Input(SHA512Context *, const uint8_t *bytes, 281 | unsigned int bytecount); 282 | extern int SHA512FinalBits(SHA512Context *, uint8_t bits, 283 | unsigned int bit_count); 284 | extern int SHA512Result(SHA512Context *, 285 | uint8_t Message_Digest[SHA512HashSize]); 286 | 287 | /* Unified SHA functions, chosen by whichSha */ 288 | extern int USHAReset(USHAContext *context, SHAversion whichSha); 289 | extern int USHAInput(USHAContext *context, 290 | const uint8_t *bytes, unsigned int bytecount); 291 | extern int USHAFinalBits(USHAContext *context, 292 | uint8_t bits, unsigned int bit_count); 293 | extern int USHAResult(USHAContext *context, 294 | uint8_t Message_Digest[USHAMaxHashSize]); 295 | extern int USHABlockSize(enum SHAversion whichSha); 296 | extern int USHAHashSize(enum SHAversion whichSha); 297 | extern int USHAHashSizeBits(enum SHAversion whichSha); 298 | extern const char *USHAHashName(enum SHAversion whichSha); 299 | 300 | 301 | /* 302 | * HMAC Keyed-Hashing for Message Authentication, RFC 2104, 303 | * for all SHAs. 304 | * This interface allows a fixed-length text input to be used. 305 | */ 306 | extern int hmac(SHAversion whichSha, /* which SHA algorithm to use */ 307 | const unsigned char *text, /* pointer to data stream */ 308 | int text_len, /* length of data stream */ 309 | const unsigned char *key, /* pointer to authentication key */ 310 | int key_len, /* length of authentication key */ 311 | uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */ 312 | 313 | /* 314 | * HMAC Keyed-Hashing for Message Authentication, RFC 2104, 315 | * for all SHAs. 316 | * This interface allows any length of text input to be used. 317 | */ 318 | extern int hmacReset(HMACContext *context, enum SHAversion whichSha, 319 | const unsigned char *key, int key_len); 320 | extern int hmacInput(HMACContext *context, const unsigned char *text, 321 | int text_len); 322 | extern int hmacFinalBits(HMACContext *context, uint8_t bits, 323 | unsigned int bit_count); 324 | extern int hmacResult(HMACContext *context, 325 | uint8_t digest[USHAMaxHashSize]); 326 | 327 | /* 328 | * HKDF HMAC-based Extract-and-Expand Key Derivation Function, 329 | * RFC 5869, for all SHAs. 330 | */ 331 | extern int hkdf(SHAversion whichSha, const unsigned char *salt, 332 | int salt_len, const unsigned char *ikm, int ikm_len, 333 | const unsigned char *info, int info_len, 334 | uint8_t okm[ ], int okm_len); 335 | extern int hkdfExtract(SHAversion whichSha, const unsigned char *salt, 336 | int salt_len, const unsigned char *ikm, 337 | int ikm_len, uint8_t prk[USHAMaxHashSize]); 338 | extern int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ], 339 | int prk_len, const unsigned char *info, 340 | int info_len, uint8_t okm[ ], int okm_len); 341 | 342 | /* 343 | * HKDF HMAC-based Extract-and-Expand Key Derivation Function, 344 | * RFC 5869, for all SHAs. 345 | * This interface allows any length of text input to be used. 346 | */ 347 | extern int hkdfReset(HKDFContext *context, enum SHAversion whichSha, 348 | const unsigned char *salt, int salt_len); 349 | 350 | extern int hkdfInput(HKDFContext *context, const unsigned char *ikm, 351 | int ikm_len); 352 | extern int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits, 353 | unsigned int ikm_bit_count); 354 | extern int hkdfResult(HKDFContext *context, 355 | uint8_t prk[USHAMaxHashSize], 356 | const unsigned char *info, int info_len, 357 | uint8_t okm[USHAMaxHashSize], int okm_len); 358 | #endif /* _SHA_H_ */ 359 | -------------------------------------------------------------------------------- /src/sha1.c: -------------------------------------------------------------------------------- 1 | /**************************** sha1.c ***************************/ 2 | /***************** See RFC 6234 for details. *******************/ 3 | // https://tools.ietf.org/html/rfc6234#section-8.2 4 | /* Copyright (c) 2011 IETF Trust and the persons identified as */ 5 | /* authors of the code. All rights reserved. */ 6 | /* See sha.h for terms of use and redistribution. */ 7 | 8 | /* 9 | * Description: 10 | * This file implements the Secure Hash Algorithm SHA-1 11 | * as defined in the U.S. National Institute of Standards 12 | * and Technology Federal Information Processing Standards 13 | * Publication (FIPS PUB) 180-3 published in October 2008 14 | * and formerly defined in its predecessors, FIPS PUB 180-1 15 | * and FIP PUB 180-2. 16 | * 17 | * A combined document showing all algorithms is available at 18 | * http://csrc.nist.gov/publications/fips/ 19 | * fips180-3/fips180-3_final.pdf 20 | * 21 | * The SHA-1 algorithm produces a 160-bit message digest for a 22 | * given data stream that can serve as a means of providing a 23 | * "fingerprint" for a message. 24 | * 25 | * Portability Issues: 26 | * SHA-1 is defined in terms of 32-bit "words". This code 27 | * uses (included via "sha.h") to define 32- and 28 | * 8-bit unsigned integer types. If your C compiler does 29 | * not support 32-bit unsigned integers, this code is not 30 | * appropriate. 31 | * 32 | * Caveats: 33 | * SHA-1 is designed to work with messages less than 2^64 bits 34 | * long. This implementation uses SHA1Input() to hash the bits 35 | * that are a multiple of the size of an 8-bit octet, and then 36 | * optionally uses SHA1FinalBits() to hash the final few bits of 37 | * the input. 38 | */ 39 | 40 | #include "sha.h" 41 | #include "sha-private.h" 42 | 43 | /* 44 | * Define the SHA1 circular left shift macro 45 | */ 46 | #define SHA1_ROTL(bits,word) \ 47 | (((word) << (bits)) | ((word) >> (32-(bits)))) 48 | 49 | /* 50 | * Add "length" to the length. 51 | * Set Corrupted when overflow has occurred. 52 | */ 53 | static uint32_t addTemp; 54 | #define SHA1AddLength(context, length) \ 55 | (addTemp = (context)->Length_Low, \ 56 | (context)->Corrupted = \ 57 | (((context)->Length_Low += (length)) < addTemp) && \ 58 | (++(context)->Length_High == 0) ? shaInputTooLong \ 59 | : (context)->Corrupted ) 60 | 61 | /* Local Function Prototypes */ 62 | static void SHA1ProcessMessageBlock(SHA1Context *context); 63 | static void SHA1Finalize(SHA1Context *context, uint8_t Pad_Byte); 64 | static void SHA1PadMessage(SHA1Context *context, uint8_t Pad_Byte); 65 | 66 | /* 67 | * SHA1Reset 68 | * 69 | * Description: 70 | * This function will initialize the SHA1Context in preparation 71 | * for computing a new SHA1 message digest. 72 | * 73 | * Parameters: 74 | * context: [in/out] 75 | * The context to reset. 76 | * 77 | * Returns: 78 | * sha Error Code. 79 | * 80 | */ 81 | int SHA1Reset(SHA1Context *context) 82 | { 83 | if (!context) return shaNull; 84 | 85 | context->Length_High = context->Length_Low = 0; 86 | context->Message_Block_Index = 0; 87 | 88 | /* Initial Hash Values: FIPS 180-3 section 5.3.1 */ 89 | context->Intermediate_Hash[0] = 0x67452301; 90 | context->Intermediate_Hash[1] = 0xEFCDAB89; 91 | context->Intermediate_Hash[2] = 0x98BADCFE; 92 | context->Intermediate_Hash[3] = 0x10325476; 93 | context->Intermediate_Hash[4] = 0xC3D2E1F0; 94 | 95 | context->Computed = 0; 96 | context->Corrupted = shaSuccess; 97 | 98 | return shaSuccess; 99 | } 100 | 101 | /* 102 | * SHA1Input 103 | * 104 | * Description: 105 | * This function accepts an array of octets as the next portion 106 | * of the message. 107 | * 108 | * Parameters: 109 | * context: [in/out] 110 | * The SHA context to update. 111 | * message_array[ ]: [in] 112 | * An array of octets representing the next portion of 113 | * the message. 114 | * length: [in] 115 | * The length of the message in message_array. 116 | * 117 | * Returns: 118 | * sha Error Code. 119 | * 120 | */ 121 | int SHA1Input(SHA1Context *context, 122 | const uint8_t *message_array, unsigned length) 123 | { 124 | if (!context) return shaNull; 125 | if (!length) return shaSuccess; 126 | if (!message_array) return shaNull; 127 | if (context->Computed) return context->Corrupted = shaStateError; 128 | if (context->Corrupted) return context->Corrupted; 129 | 130 | while (length--) { 131 | context->Message_Block[context->Message_Block_Index++] = 132 | *message_array; 133 | 134 | if ((SHA1AddLength(context, 8) == shaSuccess) && 135 | (context->Message_Block_Index == SHA1_Message_Block_Size)) 136 | SHA1ProcessMessageBlock(context); 137 | 138 | message_array++; 139 | } 140 | 141 | return context->Corrupted; 142 | } 143 | 144 | /* 145 | * SHA1FinalBits 146 | * 147 | * Description: 148 | * This function will add in any final bits of the message. 149 | * 150 | * Parameters: 151 | * context: [in/out] 152 | * The SHA context to update. 153 | * message_bits: [in] 154 | * The final bits of the message, in the upper portion of the 155 | * byte. (Use 0b###00000 instead of 0b00000### to input the 156 | * three bits ###.) 157 | * length: [in] 158 | * The number of bits in message_bits, between 1 and 7. 159 | * 160 | * Returns: 161 | * sha Error Code. 162 | */ 163 | int SHA1FinalBits(SHA1Context *context, uint8_t message_bits, 164 | unsigned int length) 165 | { 166 | static uint8_t masks[8] = { 167 | /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, 168 | /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, 169 | /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, 170 | /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE 171 | }; 172 | 173 | static uint8_t markbit[8] = { 174 | /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, 175 | /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, 176 | /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, 177 | /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 178 | }; 179 | 180 | if (!context) return shaNull; 181 | if (!length) return shaSuccess; 182 | if (context->Corrupted) return context->Corrupted; 183 | if (context->Computed) return context->Corrupted = shaStateError; 184 | if (length >= 8) return context->Corrupted = shaBadParam; 185 | 186 | SHA1AddLength(context, length); 187 | SHA1Finalize(context, 188 | (uint8_t) ((message_bits & masks[length]) | markbit[length])); 189 | 190 | return context->Corrupted; 191 | } 192 | 193 | /* 194 | * SHA1Result 195 | * 196 | * Description: 197 | * This function will return the 160-bit message digest 198 | * into the Message_Digest array provided by the caller. 199 | * NOTE: 200 | * The first octet of hash is stored in the element with index 0, 201 | * the last octet of hash in the element with index 19. 202 | * 203 | * Parameters: 204 | * context: [in/out] 205 | * The context to use to calculate the SHA-1 hash. 206 | * Message_Digest[ ]: [out] 207 | * Where the digest is returned. 208 | * 209 | * Returns: 210 | * sha Error Code. 211 | * 212 | */ 213 | int SHA1Result(SHA1Context *context, 214 | uint8_t Message_Digest[SHA1HashSize]) 215 | { 216 | int i; 217 | 218 | if (!context) return shaNull; 219 | if (!Message_Digest) return shaNull; 220 | if (context->Corrupted) return context->Corrupted; 221 | 222 | if (!context->Computed) 223 | SHA1Finalize(context, 0x80); 224 | 225 | for (i = 0; i < SHA1HashSize; ++i) 226 | Message_Digest[i] = (uint8_t) (context->Intermediate_Hash[i>>2] 227 | >> (8 * ( 3 - ( i & 0x03 ) ))); 228 | 229 | return shaSuccess; 230 | } 231 | 232 | /* 233 | * SHA1ProcessMessageBlock 234 | * 235 | * Description: 236 | * This helper function will process the next 512 bits of the 237 | * message stored in the Message_Block array. 238 | * 239 | * Parameters: 240 | * context: [in/out] 241 | * The SHA context to update. 242 | * 243 | * Returns: 244 | * Nothing. 245 | * 246 | * Comments: 247 | * Many of the variable names in this code, especially the 248 | * single character names, were used because those were the 249 | * names used in the Secure Hash Standard. 250 | */ 251 | static void SHA1ProcessMessageBlock(SHA1Context *context) 252 | { 253 | /* Constants defined in FIPS 180-3, section 4.2.1 */ 254 | const uint32_t K[4] = { 255 | 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 256 | }; 257 | 258 | int t; /* Loop counter */ 259 | uint32_t temp; /* Temporary word value */ 260 | uint32_t W[80]; /* Word sequence */ 261 | uint32_t A, B, C, D, E; /* Word buffers */ 262 | 263 | /* 264 | * Initialize the first 16 words in the array W 265 | */ 266 | for (t = 0; t < 16; t++) { 267 | W[t] = ((uint32_t)context->Message_Block[t * 4]) << 24; 268 | W[t] |= ((uint32_t)context->Message_Block[t * 4 + 1]) << 16; 269 | W[t] |= ((uint32_t)context->Message_Block[t * 4 + 2]) << 8; 270 | W[t] |= ((uint32_t)context->Message_Block[t * 4 + 3]); 271 | } 272 | 273 | for (t = 16; t < 80; t++) 274 | W[t] = SHA1_ROTL(1, W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); 275 | 276 | A = context->Intermediate_Hash[0]; 277 | B = context->Intermediate_Hash[1]; 278 | C = context->Intermediate_Hash[2]; 279 | D = context->Intermediate_Hash[3]; 280 | E = context->Intermediate_Hash[4]; 281 | 282 | for (t = 0; t < 20; t++) { 283 | temp = SHA1_ROTL(5,A) + SHA_Ch(B, C, D) + E + W[t] + K[0]; 284 | E = D; 285 | D = C; 286 | C = SHA1_ROTL(30,B); 287 | B = A; 288 | A = temp; 289 | } 290 | 291 | for (t = 20; t < 40; t++) { 292 | temp = SHA1_ROTL(5,A) + SHA_Parity(B, C, D) + E + W[t] + K[1]; 293 | E = D; 294 | D = C; 295 | C = SHA1_ROTL(30,B); 296 | B = A; 297 | A = temp; 298 | } 299 | 300 | for (t = 40; t < 60; t++) { 301 | temp = SHA1_ROTL(5,A) + SHA_Maj(B, C, D) + E + W[t] + K[2]; 302 | E = D; 303 | D = C; 304 | C = SHA1_ROTL(30,B); 305 | B = A; 306 | A = temp; 307 | } 308 | 309 | for (t = 60; t < 80; t++) { 310 | temp = SHA1_ROTL(5,A) + SHA_Parity(B, C, D) + E + W[t] + K[3]; 311 | E = D; 312 | D = C; 313 | C = SHA1_ROTL(30,B); 314 | B = A; 315 | A = temp; 316 | } 317 | 318 | context->Intermediate_Hash[0] += A; 319 | context->Intermediate_Hash[1] += B; 320 | context->Intermediate_Hash[2] += C; 321 | context->Intermediate_Hash[3] += D; 322 | context->Intermediate_Hash[4] += E; 323 | context->Message_Block_Index = 0; 324 | } 325 | 326 | /* 327 | * SHA1Finalize 328 | * 329 | * Description: 330 | * This helper function finishes off the digest calculations. 331 | * 332 | * Parameters: 333 | * context: [in/out] 334 | * The SHA context to update. 335 | * Pad_Byte: [in] 336 | * The last byte to add to the message block before the 0-padding 337 | * and length. This will contain the last bits of the message 338 | * followed by another single bit. If the message was an 339 | * exact multiple of 8-bits long, Pad_Byte will be 0x80. 340 | * 341 | * Returns: 342 | * sha Error Code. 343 | * 344 | */ 345 | static void SHA1Finalize(SHA1Context *context, uint8_t Pad_Byte) 346 | { 347 | int i; 348 | SHA1PadMessage(context, Pad_Byte); 349 | /* message may be sensitive, clear it out */ 350 | for (i = 0; i < SHA1_Message_Block_Size; ++i) 351 | context->Message_Block[i] = 0; 352 | context->Length_High = 0; /* and clear length */ 353 | context->Length_Low = 0; 354 | context->Computed = 1; 355 | } 356 | 357 | /* 358 | * SHA1PadMessage 359 | * 360 | * Description: 361 | * According to the standard, the message must be padded to the next 362 | * even multiple of 512 bits. The first padding bit must be a '1'. 363 | * The last 64 bits represent the length of the original message. 364 | * All bits in between should be 0. This helper function will pad 365 | * the message according to those rules by filling the Message_Block 366 | * array accordingly. When it returns, it can be assumed that the 367 | * message digest has been computed. 368 | * 369 | * Parameters: 370 | * context: [in/out] 371 | * The context to pad. 372 | * Pad_Byte: [in] 373 | * The last byte to add to the message block before the 0-padding 374 | * and length. This will contain the last bits of the message 375 | * followed by another single bit. If the message was an 376 | * exact multiple of 8-bits long, Pad_Byte will be 0x80. 377 | * 378 | * Returns: 379 | * Nothing. 380 | */ 381 | static void SHA1PadMessage(SHA1Context *context, uint8_t Pad_Byte) 382 | { 383 | /* 384 | * Check to see if the current message block is too small to hold 385 | * the initial padding bits and length. If so, we will pad the 386 | * block, process it, and then continue padding into a second 387 | * block. 388 | */ 389 | if (context->Message_Block_Index >= (SHA1_Message_Block_Size - 8)) { 390 | context->Message_Block[context->Message_Block_Index++] = Pad_Byte; 391 | while (context->Message_Block_Index < SHA1_Message_Block_Size) 392 | context->Message_Block[context->Message_Block_Index++] = 0; 393 | 394 | SHA1ProcessMessageBlock(context); 395 | } else 396 | context->Message_Block[context->Message_Block_Index++] = Pad_Byte; 397 | 398 | while (context->Message_Block_Index < (SHA1_Message_Block_Size - 8)) 399 | context->Message_Block[context->Message_Block_Index++] = 0; 400 | 401 | /* 402 | * Store the message length as the last 8 octets 403 | */ 404 | context->Message_Block[56] = (uint8_t) (context->Length_High >> 24); 405 | context->Message_Block[57] = (uint8_t) (context->Length_High >> 16); 406 | context->Message_Block[58] = (uint8_t) (context->Length_High >> 8); 407 | context->Message_Block[59] = (uint8_t) (context->Length_High); 408 | context->Message_Block[60] = (uint8_t) (context->Length_Low >> 24); 409 | context->Message_Block[61] = (uint8_t) (context->Length_Low >> 16); 410 | context->Message_Block[62] = (uint8_t) (context->Length_Low >> 8); 411 | context->Message_Block[63] = (uint8_t) (context->Length_Low); 412 | 413 | SHA1ProcessMessageBlock(context); 414 | } 415 | --------------------------------------------------------------------------------