├── .gitignore ├── base64.h ├── CMakeLists.txt ├── README ├── fprime.h ├── sha512.h ├── edsign.h ├── ed25519.h ├── f25519.h ├── fprime.c ├── edsign.c ├── f25519.c ├── sha512.c ├── ed25519.c ├── main.c └── base64.c /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | CMakeCache.txt 3 | CMakeFiles 4 | *.cmake 5 | *.a 6 | *.so 7 | *.dylib 8 | install_manifest.txt 9 | usign 10 | -------------------------------------------------------------------------------- /base64.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE64_H 2 | #define __BASE64_H 3 | 4 | #ifdef USE_LIBUBOX 5 | #include 6 | #else 7 | int b64_encode(const void *src, size_t src_len, 8 | void *dest, size_t dest_len); 9 | 10 | int b64_decode(const void *src, void *dest, size_t dest_len); 11 | 12 | #define B64_ENCODE_LEN(_len) ((((_len) + 2) / 3) * 4 + 1) 13 | #define B64_DECODE_LEN(_len) (((_len) / 4) * 3 + 1) 14 | #endif /* USE_LIBUBOX */ 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | PROJECT(usign C) 4 | ADD_DEFINITIONS(-O2 -Wall -Werror --std=gnu99 -g3 -Wmissing-declarations) 5 | 6 | SET(SOURCES ed25519.c edsign.c f25519.c fprime.c sha512.c main.c) 7 | 8 | SET(LIBS) 9 | IF(USE_LIBUBOX) 10 | ADD_DEFINITIONS(-DUSE_LIBUBOX) 11 | SET(LIBS ubox) 12 | FIND_PATH(ubox_include_dir libubox/utils.h) 13 | INCLUDE_DIRECTORIES(${ubox_include_dir}) 14 | ELSE() 15 | SET(SOURCES ${SOURCES} base64.c) 16 | ENDIF() 17 | 18 | ADD_EXECUTABLE(usign ${SOURCES}) 19 | TARGET_LINK_LIBRARIES(usign ${LIBS}) 20 | 21 | INSTALL(TARGETS usign 22 | RUNTIME DESTINATION bin 23 | ) 24 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Usign provides public key signatures using the ed25519 algorithm. 2 | 3 | The home page for the algorithm is http://ed25519.cr.yp.to/. 4 | It is described in the following paper: 5 | 6 | Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, Bo-Yin Yang 7 | High-speed high-security signatures 8 | Journal of Cryptographic Engineering 2 (2012), 77-89 9 | 2011-09-26 10 | http://ed25519.cr.yp.to/ed25519-20110926.pdf 11 | 12 | Signatures and keys are compatible to OpenBSD's signify utility: 13 | http://man.openbsd.org/OpenBSD-current/man1/signify.1 14 | 15 | To build and install the package run 16 | 17 | mkdir build 18 | cd build 19 | cmake .. 20 | make 21 | sudo make install 22 | -------------------------------------------------------------------------------- /fprime.h: -------------------------------------------------------------------------------- 1 | /* Arithmetic in prime fields 2 | * Daniel Beer , 10 Jan 2014 3 | * 4 | * This file is in the public domain. 5 | */ 6 | 7 | #ifndef FPRIME_H_ 8 | #define FPRIME_H_ 9 | 10 | #include 11 | #include 12 | 13 | /* Maximum size of a field element (or a prime). Field elements are 14 | * always manipulated and stored in normalized form, with 0 <= x < p. 15 | * You can use normalize() to convert a denormalized bitstring to normal 16 | * form. 17 | * 18 | * Operations are constant with respect to the value of field elements, 19 | * but not with respect to the modulus. 20 | * 21 | * The modulus is a number p, such that 2p-1 fits in FPRIME_SIZE bytes. 22 | */ 23 | #define FPRIME_SIZE 32 24 | 25 | /* Load a large constant */ 26 | void fprime_from_bytes(uint8_t *x, 27 | const uint8_t *in, size_t len, 28 | const uint8_t *modulus); 29 | 30 | /* Copy an element */ 31 | static inline void fprime_copy(uint8_t *x, const uint8_t *a) 32 | { 33 | memcpy(x, a, FPRIME_SIZE); 34 | } 35 | 36 | /* Compare two field points in constant time. Return one if equal, zero 37 | * otherwise. This should be performed only on normalized values. 38 | */ 39 | uint8_t fprime_eq(const uint8_t *x, const uint8_t *y); 40 | 41 | /* Conditional copy. If condition == 0, then zero is copied to dst. If 42 | * condition == 1, then one is copied to dst. Any other value results in 43 | * undefined behaviour. 44 | */ 45 | void fprime_select(uint8_t *dst, 46 | const uint8_t *zero, const uint8_t *one, 47 | uint8_t condition); 48 | 49 | /* Add one value to another. The two pointers must be distinct. */ 50 | void fprime_add(uint8_t *r, const uint8_t *a, const uint8_t *modulus); 51 | 52 | /* Multiply two values to get a third. r must be distinct from a and b */ 53 | void fprime_mul(uint8_t *r, const uint8_t *a, const uint8_t *b, 54 | const uint8_t *modulus); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /sha512.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Felix Fietkau 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* SHA512 18 | * Daniel Beer , 22 Apr 2014 19 | * 20 | * This file is in the public domain. 21 | */ 22 | 23 | #ifndef SHA512_H_ 24 | #define SHA512_H_ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | /* Feed a full block in */ 32 | #define SHA512_BLOCK_SIZE 128 33 | 34 | /* SHA512 state. State is updated as data is fed in, and then the final 35 | * hash can be read out in slices. 36 | * 37 | * Data is fed in as a sequence of full blocks terminated by a single 38 | * partial block. 39 | */ 40 | struct sha512_state { 41 | uint64_t h[8]; 42 | uint8_t partial[SHA512_BLOCK_SIZE]; 43 | size_t len; 44 | }; 45 | 46 | /* Set up a new context */ 47 | void sha512_init(struct sha512_state *s); 48 | 49 | void sha512_add(struct sha512_state *s, const void *data, size_t len); 50 | 51 | /* Fetch a slice of the hash result. */ 52 | #define SHA512_HASH_SIZE 64 53 | 54 | void sha512_final(struct sha512_state *s, uint8_t *hash); 55 | 56 | static inline void * 57 | sha512_final_get(struct sha512_state *s) 58 | { 59 | sha512_final(s, s->partial); 60 | return s->partial; 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /edsign.h: -------------------------------------------------------------------------------- 1 | /* Edwards curve signature system 2 | * Daniel Beer , 22 Apr 2014 3 | * 4 | * This file is in the public domain. 5 | */ 6 | 7 | #ifndef EDSIGN_H_ 8 | #define EDSIGN_H_ 9 | 10 | #include 11 | #include 12 | #include "sha512.h" 13 | 14 | /* This is the Ed25519 signature system, as described in: 15 | * 16 | * Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, Bo-Yin 17 | * Yang. High-speed high-security signatures. Journal of Cryptographic 18 | * Engineering 2 (2012), 77–89. Document ID: 19 | * a1a62a2f76d23f65d622484ddd09caf8. URL: 20 | * http://cr.yp.to/papers.html#ed25519. Date: 2011.09.26. 21 | * 22 | * The format and calculation of signatures is compatible with the 23 | * Ed25519 implementation in SUPERCOP. Note, however, that our secret 24 | * keys are half the size: we don't store a copy of the public key in 25 | * the secret key (we generate it on demand). 26 | */ 27 | 28 | /* Any string of 32 random bytes is a valid secret key. There is no 29 | * clamping of bits, because we don't use the key directly as an 30 | * exponent (the exponent is derived from part of a key expansion). 31 | */ 32 | #define EDSIGN_SECRET_KEY_SIZE 32 33 | 34 | /* Given a secret key, produce the public key (a packed Edwards-curve 35 | * point). 36 | */ 37 | #define EDSIGN_PUBLIC_KEY_SIZE 32 38 | 39 | void edsign_sec_to_pub(void *pub, const void *secret); 40 | 41 | /* Produce a signature for a message. */ 42 | #define EDSIGN_SIGNATURE_SIZE 64 43 | 44 | void edsign_sign(uint8_t *signature, const uint8_t *pub, 45 | const uint8_t *secret, 46 | const uint8_t *message, size_t len); 47 | 48 | struct edsign_verify_state { 49 | struct sha512_state sha; 50 | }; 51 | 52 | void edsign_verify_init(struct edsign_verify_state *st, const void *sig, 53 | const void *pub); 54 | 55 | static inline void 56 | edsign_verify_add(struct edsign_verify_state *st, const void *data, int len) 57 | { 58 | sha512_add(&st->sha, data, len); 59 | } 60 | 61 | /* Verify a message signature. Returns non-zero if ok. */ 62 | bool edsign_verify(struct edsign_verify_state *st, const void *sig, const void *pub); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /ed25519.h: -------------------------------------------------------------------------------- 1 | /* Edwards curve operations 2 | * Daniel Beer , 9 Jan 2014 3 | * 4 | * This file is in the public domain. 5 | */ 6 | 7 | #ifndef ED25519_H_ 8 | #define ED25519_H_ 9 | 10 | #include "f25519.h" 11 | 12 | /* This is not the Ed25519 signature system. Rather, we're implementing 13 | * basic operations on the twisted Edwards curve over (Z mod 2^255-19): 14 | * 15 | * -x^2 + y^2 = 1 - (121665/121666)x^2y^2 16 | * 17 | * With the positive-x base point y = 4/5. 18 | * 19 | * These functions will not leak secret data through timing. 20 | * 21 | * For more information, see: 22 | * 23 | * Bernstein, D.J. & Lange, T. (2007) "Faster addition and doubling on 24 | * elliptic curves". Document ID: 95616567a6ba20f575c5f25e7cebaf83. 25 | * 26 | * Hisil, H. & Wong, K K. & Carter, G. & Dawson, E. (2008) "Twisted 27 | * Edwards curves revisited". Advances in Cryptology, ASIACRYPT 2008, 28 | * Vol. 5350, pp. 326-343. 29 | */ 30 | 31 | /* Projective coordinates */ 32 | struct ed25519_pt { 33 | uint8_t x[F25519_SIZE]; 34 | uint8_t y[F25519_SIZE]; 35 | uint8_t t[F25519_SIZE]; 36 | uint8_t z[F25519_SIZE]; 37 | }; 38 | 39 | extern const struct ed25519_pt ed25519_base; 40 | 41 | /* Convert between projective and affine coordinates (x/y in F25519) */ 42 | void ed25519_project(struct ed25519_pt *p, 43 | const uint8_t *x, const uint8_t *y); 44 | 45 | void ed25519_unproject(uint8_t *x, uint8_t *y, 46 | const struct ed25519_pt *p); 47 | 48 | /* Compress/uncompress points. try_unpack() will check that the 49 | * compressed point is on the curve, returning 1 if the unpacked point 50 | * is valid, and 0 otherwise. 51 | */ 52 | #define ED25519_PACK_SIZE F25519_SIZE 53 | 54 | void ed25519_pack(uint8_t *c, const uint8_t *x, const uint8_t *y); 55 | uint8_t ed25519_try_unpack(uint8_t *x, uint8_t *y, const uint8_t *c); 56 | 57 | /* Add, double and scalar multiply */ 58 | #define ED25519_EXPONENT_SIZE 32 59 | 60 | /* Prepare an exponent by clamping appropriate bits */ 61 | static inline void ed25519_prepare(uint8_t *e) 62 | { 63 | e[0] &= 0xf8; 64 | e[31] &= 0x7f; 65 | e[31] |= 0x40; 66 | } 67 | 68 | /* Order of the group generated by the base point */ 69 | static inline void ed25519_copy(struct ed25519_pt *dst, 70 | const struct ed25519_pt *src) 71 | { 72 | memcpy(dst, src, sizeof(*dst)); 73 | } 74 | 75 | void ed25519_add(struct ed25519_pt *r, 76 | const struct ed25519_pt *a, const struct ed25519_pt *b); 77 | void ed25519_smult(struct ed25519_pt *r, const struct ed25519_pt *a, 78 | const uint8_t *e); 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /f25519.h: -------------------------------------------------------------------------------- 1 | /* Arithmetic mod p = 2^255-19 2 | * Daniel Beer , 8 Jan 2014 3 | * 4 | * This file is in the public domain. 5 | */ 6 | 7 | #ifndef F25519_H_ 8 | #define F25519_H_ 9 | 10 | #include 11 | #include 12 | 13 | /* Field elements are represented as little-endian byte strings. All 14 | * operations have timings which are independent of input data, so they 15 | * can be safely used for cryptography. 16 | * 17 | * Computation is performed on un-normalized elements. These are byte 18 | * strings which fall into the range 0 <= x < 2p. Use f25519_normalize() 19 | * to convert to a value 0 <= x < p. 20 | * 21 | * Elements received from the outside may greater even than 2p. 22 | * f25519_normalize() will correctly deal with these numbers too. 23 | */ 24 | #define F25519_SIZE 32 25 | 26 | /* Identity constants */ 27 | extern const uint8_t f25519_one[F25519_SIZE]; 28 | 29 | /* Load a small constant */ 30 | void f25519_load(uint8_t *x, uint32_t c); 31 | 32 | /* Copy two points */ 33 | static inline void f25519_copy(uint8_t *x, const uint8_t *a) 34 | { 35 | memcpy(x, a, F25519_SIZE); 36 | } 37 | 38 | /* Normalize a field point x < 2*p by subtracting p if necessary */ 39 | void f25519_normalize(uint8_t *x); 40 | 41 | /* Compare two field points in constant time. Return one if equal, zero 42 | * otherwise. This should be performed only on normalized values. 43 | */ 44 | uint8_t f25519_eq(const uint8_t *x, const uint8_t *y); 45 | 46 | /* Conditional copy. If condition == 0, then zero is copied to dst. If 47 | * condition == 1, then one is copied to dst. Any other value results in 48 | * undefined behaviour. 49 | */ 50 | void f25519_select(uint8_t *dst, 51 | const uint8_t *zero, const uint8_t *one, 52 | uint8_t condition); 53 | 54 | /* Add/subtract two field points. The three pointers are not required to 55 | * be distinct. 56 | */ 57 | void f25519_add(uint8_t *r, const uint8_t *a, const uint8_t *b); 58 | void f25519_sub(uint8_t *r, const uint8_t *a, const uint8_t *b); 59 | 60 | /* Unary negation */ 61 | void f25519_neg(uint8_t *r, const uint8_t *a); 62 | 63 | /* Multiply two field points. The __distinct variant is used when r is 64 | * known to be in a different location to a and b. 65 | */ 66 | void f25519_mul__distinct(uint8_t *r, const uint8_t *a, const uint8_t *b); 67 | 68 | /* Take the reciprocal of a field point. The __distinct variant is used 69 | * when r is known to be in a different location to x. 70 | */ 71 | void f25519_inv__distinct(uint8_t *r, const uint8_t *x); 72 | 73 | /* Compute one of the square roots of the field element, if the element 74 | * is square. The other square is -r. 75 | * 76 | * If the input is not square, the returned value is a valid field 77 | * element, but not the correct answer. If you don't already know that 78 | * your element is square, you should square the return value and test. 79 | */ 80 | void f25519_sqrt(uint8_t *r, const uint8_t *x); 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /fprime.c: -------------------------------------------------------------------------------- 1 | /* Arithmetic in prime fields 2 | * Daniel Beer , 10 Jan 2014 3 | * 4 | * This file is in the public domain. 5 | */ 6 | 7 | #include "fprime.h" 8 | 9 | static void raw_add(uint8_t *x, const uint8_t *p) 10 | { 11 | uint16_t c = 0; 12 | int i; 13 | 14 | for (i = 0; i < FPRIME_SIZE; i++) { 15 | c += ((uint16_t)x[i]) + ((uint16_t)p[i]); 16 | x[i] = c; 17 | c >>= 8; 18 | } 19 | } 20 | 21 | static void raw_try_sub(uint8_t *x, const uint8_t *p) 22 | { 23 | uint8_t minusp[FPRIME_SIZE]; 24 | uint16_t c = 0; 25 | int i; 26 | 27 | for (i = 0; i < FPRIME_SIZE; i++) { 28 | c = ((uint16_t)x[i]) - ((uint16_t)p[i]) - c; 29 | minusp[i] = c; 30 | c = (c >> 8) & 1; 31 | } 32 | 33 | fprime_select(x, minusp, x, c); 34 | } 35 | 36 | /* Warning: this function is variable-time */ 37 | static int prime_msb(const uint8_t *p) 38 | { 39 | int i; 40 | uint8_t x; 41 | 42 | for (i = FPRIME_SIZE - 1; i >= 0; i--) 43 | if (p[i]) 44 | break; 45 | 46 | x = p[i]; 47 | i <<= 3; 48 | 49 | while (x) { 50 | x >>= 1; 51 | i++; 52 | } 53 | 54 | return i - 1; 55 | } 56 | 57 | /* Warning: this function may be variable-time in the argument n */ 58 | static void shift_n_bits(uint8_t *x, int n) 59 | { 60 | uint16_t c = 0; 61 | int i; 62 | 63 | for (i = 0; i < FPRIME_SIZE; i++) { 64 | c |= ((uint16_t)x[i]) << n; 65 | x[i] = c; 66 | c >>= 8; 67 | } 68 | } 69 | 70 | static inline int min_int(int a, int b) 71 | { 72 | return a < b ? a : b; 73 | } 74 | 75 | void fprime_from_bytes(uint8_t *n, 76 | const uint8_t *x, size_t len, 77 | const uint8_t *modulus) 78 | { 79 | const int preload_total = min_int(prime_msb(modulus) - 1, len << 3); 80 | const int preload_bytes = preload_total >> 3; 81 | const int preload_bits = preload_total & 7; 82 | const int rbits = (len << 3) - preload_total; 83 | int i; 84 | 85 | memset(n, 0, FPRIME_SIZE); 86 | 87 | for (i = 0; i < preload_bytes; i++) 88 | n[i] = x[len - preload_bytes + i]; 89 | 90 | if (preload_bits) { 91 | shift_n_bits(n, preload_bits); 92 | n[0] |= x[len - preload_bytes - 1] >> (8 - preload_bits); 93 | } 94 | 95 | for (i = rbits - 1; i >= 0; i--) { 96 | const uint8_t bit = (x[i >> 3] >> (i & 7)) & 1; 97 | 98 | shift_n_bits(n, 1); 99 | n[0] |= bit; 100 | raw_try_sub(n, modulus); 101 | } 102 | } 103 | 104 | void fprime_select(uint8_t *dst, 105 | const uint8_t *zero, const uint8_t *one, 106 | uint8_t condition) 107 | { 108 | const uint8_t mask = -condition; 109 | int i; 110 | 111 | for (i = 0; i < FPRIME_SIZE; i++) 112 | dst[i] = zero[i] ^ (mask & (one[i] ^ zero[i])); 113 | } 114 | 115 | void fprime_add(uint8_t *r, const uint8_t *a, const uint8_t *modulus) 116 | { 117 | raw_add(r, a); 118 | raw_try_sub(r, modulus); 119 | } 120 | 121 | void fprime_mul(uint8_t *r, const uint8_t *a, const uint8_t *b, 122 | const uint8_t *modulus) 123 | { 124 | int i; 125 | 126 | memset(r, 0, FPRIME_SIZE); 127 | 128 | for (i = prime_msb(modulus); i >= 0; i--) { 129 | const uint8_t bit = (b[i >> 3] >> (i & 7)) & 1; 130 | uint8_t plusa[FPRIME_SIZE]; 131 | 132 | shift_n_bits(r, 1); 133 | raw_try_sub(r, modulus); 134 | 135 | fprime_copy(plusa, r); 136 | fprime_add(plusa, a, modulus); 137 | 138 | fprime_select(r, r, plusa, bit); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /edsign.c: -------------------------------------------------------------------------------- 1 | /* Edwards curve signature system 2 | * Daniel Beer , 22 Apr 2014 3 | * 4 | * This file is in the public domain. 5 | */ 6 | 7 | #include "ed25519.h" 8 | #include "sha512.h" 9 | #include "fprime.h" 10 | #include "edsign.h" 11 | 12 | #define EXPANDED_SIZE 64 13 | 14 | static const uint8_t ed25519_order[FPRIME_SIZE] = { 15 | 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 16 | 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 17 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 18 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 19 | }; 20 | 21 | static void expand_key(uint8_t *expanded, const uint8_t *secret) 22 | { 23 | struct sha512_state s; 24 | 25 | sha512_init(&s); 26 | sha512_add(&s, secret, EDSIGN_SECRET_KEY_SIZE); 27 | sha512_final(&s, expanded); 28 | 29 | ed25519_prepare(expanded); 30 | } 31 | 32 | static uint8_t upp(struct ed25519_pt *p, const uint8_t *packed) 33 | { 34 | uint8_t x[F25519_SIZE]; 35 | uint8_t y[F25519_SIZE]; 36 | uint8_t ok = ed25519_try_unpack(x, y, packed); 37 | 38 | ed25519_project(p, x, y); 39 | return ok; 40 | } 41 | 42 | static void pp(uint8_t *packed, const struct ed25519_pt *p) 43 | { 44 | uint8_t x[F25519_SIZE]; 45 | uint8_t y[F25519_SIZE]; 46 | 47 | ed25519_unproject(x, y, p); 48 | ed25519_pack(packed, x, y); 49 | } 50 | 51 | static void sm_pack(uint8_t *r, const uint8_t *k) 52 | { 53 | struct ed25519_pt p; 54 | 55 | ed25519_smult(&p, &ed25519_base, k); 56 | pp(r, &p); 57 | } 58 | 59 | void edsign_sec_to_pub(void *pub, const void *secret) 60 | { 61 | uint8_t expanded[EXPANDED_SIZE]; 62 | 63 | expand_key(expanded, secret); 64 | sm_pack(pub, expanded); 65 | } 66 | 67 | static void save_hash(struct sha512_state *s, uint8_t *out) 68 | { 69 | void *hash; 70 | 71 | hash = sha512_final_get(s); 72 | fprime_from_bytes(out, hash, SHA512_HASH_SIZE, ed25519_order); 73 | } 74 | 75 | static void generate_k(uint8_t *k, const uint8_t *kgen_key, 76 | const uint8_t *message, size_t len) 77 | { 78 | struct sha512_state s; 79 | 80 | sha512_init(&s); 81 | sha512_add(&s, kgen_key, 32); 82 | sha512_add(&s, message, len); 83 | save_hash(&s, k); 84 | } 85 | 86 | static void hash_message(uint8_t *z, const uint8_t *r, const uint8_t *a, 87 | const uint8_t *m, size_t len) 88 | { 89 | struct sha512_state s; 90 | 91 | sha512_init(&s); 92 | sha512_add(&s, r, 32); 93 | sha512_add(&s, a, 32); 94 | sha512_add(&s, m, len); 95 | save_hash(&s, z); 96 | } 97 | 98 | void edsign_sign(uint8_t *signature, const uint8_t *pub, 99 | const uint8_t *secret, 100 | const uint8_t *message, size_t len) 101 | { 102 | uint8_t expanded[EXPANDED_SIZE]; 103 | uint8_t e[FPRIME_SIZE]; 104 | uint8_t s[FPRIME_SIZE]; 105 | uint8_t k[FPRIME_SIZE]; 106 | uint8_t z[FPRIME_SIZE]; 107 | 108 | expand_key(expanded, secret); 109 | 110 | /* Generate k and R = kB */ 111 | generate_k(k, expanded + 32, message, len); 112 | sm_pack(signature, k); 113 | 114 | /* Compute z = H(R, A, M) */ 115 | hash_message(z, signature, pub, message, len); 116 | 117 | /* Obtain e */ 118 | fprime_from_bytes(e, expanded, 32, ed25519_order); 119 | 120 | /* Compute s = ze + k */ 121 | fprime_mul(s, z, e, ed25519_order); 122 | fprime_add(s, k, ed25519_order); 123 | memcpy(signature + 32, s, 32); 124 | } 125 | 126 | void edsign_verify_init(struct edsign_verify_state *st, const void *sig, 127 | const void *pub) 128 | { 129 | sha512_init(&st->sha); 130 | sha512_add(&st->sha, sig, 32); 131 | sha512_add(&st->sha, pub, 32); 132 | } 133 | 134 | bool edsign_verify(struct edsign_verify_state *st, const void *sig, const void *pub) 135 | { 136 | struct ed25519_pt p; 137 | struct ed25519_pt q; 138 | uint8_t lhs[F25519_SIZE]; 139 | uint8_t rhs[F25519_SIZE]; 140 | uint8_t z[FPRIME_SIZE]; 141 | uint8_t ok = 1; 142 | 143 | /* Compute z = H(R, A, M) */ 144 | save_hash(&st->sha, z); 145 | 146 | /* sB = (ze + k)B = ... */ 147 | sm_pack(lhs, sig + 32); 148 | 149 | /* ... = zA + R */ 150 | ok &= upp(&p, pub); 151 | ed25519_smult(&p, &p, z); 152 | ok &= upp(&q, sig); 153 | ed25519_add(&p, &p, &q); 154 | pp(rhs, &p); 155 | 156 | /* Equal? */ 157 | return ok & f25519_eq(lhs, rhs); 158 | } 159 | -------------------------------------------------------------------------------- /f25519.c: -------------------------------------------------------------------------------- 1 | /* Arithmetic mod p = 2^255-19 2 | * Daniel Beer , 5 Jan 2014 3 | * 4 | * This file is in the public domain. 5 | */ 6 | 7 | #include "f25519.h" 8 | 9 | const uint8_t f25519_one[F25519_SIZE] = {1}; 10 | 11 | void f25519_load(uint8_t *x, uint32_t c) 12 | { 13 | int i; 14 | 15 | for (i = 0; i < sizeof(c); i++) { 16 | x[i] = c; 17 | c >>= 8; 18 | } 19 | 20 | for (; i < F25519_SIZE; i++) 21 | x[i] = 0; 22 | } 23 | 24 | void f25519_normalize(uint8_t *x) 25 | { 26 | uint8_t minusp[F25519_SIZE]; 27 | uint16_t c; 28 | int i; 29 | 30 | /* Reduce using 2^255 = 19 mod p */ 31 | c = (x[31] >> 7) * 19; 32 | x[31] &= 127; 33 | 34 | for (i = 0; i < F25519_SIZE; i++) { 35 | c += x[i]; 36 | x[i] = c; 37 | c >>= 8; 38 | } 39 | 40 | /* The number is now less than 2^255 + 18, and therefore less than 41 | * 2p. Try subtracting p, and conditionally load the subtracted 42 | * value if underflow did not occur. 43 | */ 44 | c = 19; 45 | 46 | for (i = 0; i + 1 < F25519_SIZE; i++) { 47 | c += x[i]; 48 | minusp[i] = c; 49 | c >>= 8; 50 | } 51 | 52 | c += ((uint16_t)x[i]) - 128; 53 | minusp[31] = c; 54 | 55 | /* Load x-p if no underflow */ 56 | f25519_select(x, minusp, x, (c >> 15) & 1); 57 | } 58 | 59 | uint8_t f25519_eq(const uint8_t *x, const uint8_t *y) 60 | { 61 | uint8_t sum = 0; 62 | int i; 63 | 64 | for (i = 0; i < F25519_SIZE; i++) 65 | sum |= x[i] ^ y[i]; 66 | 67 | sum |= (sum >> 4); 68 | sum |= (sum >> 2); 69 | sum |= (sum >> 1); 70 | 71 | return (sum ^ 1) & 1; 72 | } 73 | 74 | void f25519_select(uint8_t *dst, 75 | const uint8_t *zero, const uint8_t *one, 76 | uint8_t condition) 77 | { 78 | const uint8_t mask = -condition; 79 | int i; 80 | 81 | for (i = 0; i < F25519_SIZE; i++) 82 | dst[i] = zero[i] ^ (mask & (one[i] ^ zero[i])); 83 | } 84 | 85 | void f25519_add(uint8_t *r, const uint8_t *a, const uint8_t *b) 86 | { 87 | uint16_t c = 0; 88 | int i; 89 | 90 | /* Add */ 91 | for (i = 0; i < F25519_SIZE; i++) { 92 | c >>= 8; 93 | c += ((uint16_t)a[i]) + ((uint16_t)b[i]); 94 | r[i] = c; 95 | } 96 | 97 | /* Reduce with 2^255 = 19 mod p */ 98 | r[31] &= 127; 99 | c = (c >> 7) * 19; 100 | 101 | for (i = 0; i < F25519_SIZE; i++) { 102 | c += r[i]; 103 | r[i] = c; 104 | c >>= 8; 105 | } 106 | } 107 | 108 | void f25519_sub(uint8_t *r, const uint8_t *a, const uint8_t *b) 109 | { 110 | uint32_t c = 0; 111 | int i; 112 | 113 | /* Calculate a + 2p - b, to avoid underflow */ 114 | c = 218; 115 | for (i = 0; i + 1 < F25519_SIZE; i++) { 116 | c += 65280 + ((uint32_t)a[i]) - ((uint32_t)b[i]); 117 | r[i] = c; 118 | c >>= 8; 119 | } 120 | 121 | c += ((uint32_t)a[31]) - ((uint32_t)b[31]); 122 | r[31] = c & 127; 123 | c = (c >> 7) * 19; 124 | 125 | for (i = 0; i < F25519_SIZE; i++) { 126 | c += r[i]; 127 | r[i] = c; 128 | c >>= 8; 129 | } 130 | } 131 | 132 | void f25519_neg(uint8_t *r, const uint8_t *a) 133 | { 134 | uint32_t c = 0; 135 | int i; 136 | 137 | /* Calculate 2p - a, to avoid underflow */ 138 | c = 218; 139 | for (i = 0; i + 1 < F25519_SIZE; i++) { 140 | c += 65280 - ((uint32_t)a[i]); 141 | r[i] = c; 142 | c >>= 8; 143 | } 144 | 145 | c -= ((uint32_t)a[31]); 146 | r[31] = c & 127; 147 | c = (c >> 7) * 19; 148 | 149 | for (i = 0; i < F25519_SIZE; i++) { 150 | c += r[i]; 151 | r[i] = c; 152 | c >>= 8; 153 | } 154 | } 155 | 156 | void f25519_mul__distinct(uint8_t *r, const uint8_t *a, const uint8_t *b) 157 | { 158 | uint32_t c = 0; 159 | int i; 160 | 161 | for (i = 0; i < F25519_SIZE; i++) { 162 | int j; 163 | 164 | c >>= 8; 165 | for (j = 0; j <= i; j++) 166 | c += ((uint32_t)a[j]) * ((uint32_t)b[i - j]); 167 | 168 | for (; j < F25519_SIZE; j++) 169 | c += ((uint32_t)a[j]) * 170 | ((uint32_t)b[i + F25519_SIZE - j]) * 38; 171 | 172 | r[i] = c; 173 | } 174 | 175 | r[31] &= 127; 176 | c = (c >> 7) * 19; 177 | 178 | for (i = 0; i < F25519_SIZE; i++) { 179 | c += r[i]; 180 | r[i] = c; 181 | c >>= 8; 182 | } 183 | } 184 | 185 | static void f25519_mul_c(uint8_t *r, const uint8_t *a, uint32_t b) 186 | { 187 | uint32_t c = 0; 188 | int i; 189 | 190 | for (i = 0; i < F25519_SIZE; i++) { 191 | c >>= 8; 192 | c += b * ((uint32_t)a[i]); 193 | r[i] = c; 194 | } 195 | 196 | r[31] &= 127; 197 | c >>= 7; 198 | c *= 19; 199 | 200 | for (i = 0; i < F25519_SIZE; i++) { 201 | c += r[i]; 202 | r[i] = c; 203 | c >>= 8; 204 | } 205 | } 206 | 207 | void f25519_inv__distinct(uint8_t *r, const uint8_t *x) 208 | { 209 | uint8_t s[F25519_SIZE]; 210 | int i; 211 | 212 | /* This is a prime field, so by Fermat's little theorem: 213 | * 214 | * x^(p-1) = 1 mod p 215 | * 216 | * Therefore, raise to (p-2) = 2^255-21 to get a multiplicative 217 | * inverse. 218 | * 219 | * This is a 255-bit binary number with the digits: 220 | * 221 | * 11111111... 01011 222 | * 223 | * We compute the result by the usual binary chain, but 224 | * alternate between keeping the accumulator in r and s, so as 225 | * to avoid copying temporaries. 226 | */ 227 | 228 | /* 1 1 */ 229 | f25519_mul__distinct(s, x, x); 230 | f25519_mul__distinct(r, s, x); 231 | 232 | /* 1 x 248 */ 233 | for (i = 0; i < 248; i++) { 234 | f25519_mul__distinct(s, r, r); 235 | f25519_mul__distinct(r, s, x); 236 | } 237 | 238 | /* 0 */ 239 | f25519_mul__distinct(s, r, r); 240 | 241 | /* 1 */ 242 | f25519_mul__distinct(r, s, s); 243 | f25519_mul__distinct(s, r, x); 244 | 245 | /* 0 */ 246 | f25519_mul__distinct(r, s, s); 247 | 248 | /* 1 */ 249 | f25519_mul__distinct(s, r, r); 250 | f25519_mul__distinct(r, s, x); 251 | 252 | /* 1 */ 253 | f25519_mul__distinct(s, r, r); 254 | f25519_mul__distinct(r, s, x); 255 | } 256 | 257 | /* Raise x to the power of (p-5)/8 = 2^252-3, using s for temporary 258 | * storage. 259 | */ 260 | static void exp2523(uint8_t *r, const uint8_t *x, uint8_t *s) 261 | { 262 | int i; 263 | 264 | /* This number is a 252-bit number with the binary expansion: 265 | * 266 | * 111111... 01 267 | */ 268 | 269 | /* 1 1 */ 270 | f25519_mul__distinct(r, x, x); 271 | f25519_mul__distinct(s, r, x); 272 | 273 | /* 1 x 248 */ 274 | for (i = 0; i < 248; i++) { 275 | f25519_mul__distinct(r, s, s); 276 | f25519_mul__distinct(s, r, x); 277 | } 278 | 279 | /* 0 */ 280 | f25519_mul__distinct(r, s, s); 281 | 282 | /* 1 */ 283 | f25519_mul__distinct(s, r, r); 284 | f25519_mul__distinct(r, s, x); 285 | } 286 | 287 | void f25519_sqrt(uint8_t *r, const uint8_t *a) 288 | { 289 | uint8_t v[F25519_SIZE]; 290 | uint8_t i[F25519_SIZE]; 291 | uint8_t x[F25519_SIZE]; 292 | uint8_t y[F25519_SIZE]; 293 | 294 | /* v = (2a)^((p-5)/8) [x = 2a] */ 295 | f25519_mul_c(x, a, 2); 296 | exp2523(v, x, y); 297 | 298 | /* i = 2av^2 - 1 */ 299 | f25519_mul__distinct(y, v, v); 300 | f25519_mul__distinct(i, x, y); 301 | f25519_load(y, 1); 302 | f25519_sub(i, i, y); 303 | 304 | /* r = avi */ 305 | f25519_mul__distinct(x, v, a); 306 | f25519_mul__distinct(r, x, i); 307 | } 308 | -------------------------------------------------------------------------------- /sha512.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Felix Fietkau 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* SHA512 18 | * Daniel Beer , 22 Apr 2014 19 | * 20 | * This file is in the public domain. 21 | */ 22 | 23 | #include "sha512.h" 24 | 25 | static const uint64_t sha512_initial_state[8] = { 26 | 0x6a09e667f3bcc908LL, 0xbb67ae8584caa73bLL, 27 | 0x3c6ef372fe94f82bLL, 0xa54ff53a5f1d36f1LL, 28 | 0x510e527fade682d1LL, 0x9b05688c2b3e6c1fLL, 29 | 0x1f83d9abfb41bd6bLL, 0x5be0cd19137e2179LL, 30 | }; 31 | 32 | static const uint64_t round_k[80] = { 33 | 0x428a2f98d728ae22LL, 0x7137449123ef65cdLL, 34 | 0xb5c0fbcfec4d3b2fLL, 0xe9b5dba58189dbbcLL, 35 | 0x3956c25bf348b538LL, 0x59f111f1b605d019LL, 36 | 0x923f82a4af194f9bLL, 0xab1c5ed5da6d8118LL, 37 | 0xd807aa98a3030242LL, 0x12835b0145706fbeLL, 38 | 0x243185be4ee4b28cLL, 0x550c7dc3d5ffb4e2LL, 39 | 0x72be5d74f27b896fLL, 0x80deb1fe3b1696b1LL, 40 | 0x9bdc06a725c71235LL, 0xc19bf174cf692694LL, 41 | 0xe49b69c19ef14ad2LL, 0xefbe4786384f25e3LL, 42 | 0x0fc19dc68b8cd5b5LL, 0x240ca1cc77ac9c65LL, 43 | 0x2de92c6f592b0275LL, 0x4a7484aa6ea6e483LL, 44 | 0x5cb0a9dcbd41fbd4LL, 0x76f988da831153b5LL, 45 | 0x983e5152ee66dfabLL, 0xa831c66d2db43210LL, 46 | 0xb00327c898fb213fLL, 0xbf597fc7beef0ee4LL, 47 | 0xc6e00bf33da88fc2LL, 0xd5a79147930aa725LL, 48 | 0x06ca6351e003826fLL, 0x142929670a0e6e70LL, 49 | 0x27b70a8546d22ffcLL, 0x2e1b21385c26c926LL, 50 | 0x4d2c6dfc5ac42aedLL, 0x53380d139d95b3dfLL, 51 | 0x650a73548baf63deLL, 0x766a0abb3c77b2a8LL, 52 | 0x81c2c92e47edaee6LL, 0x92722c851482353bLL, 53 | 0xa2bfe8a14cf10364LL, 0xa81a664bbc423001LL, 54 | 0xc24b8b70d0f89791LL, 0xc76c51a30654be30LL, 55 | 0xd192e819d6ef5218LL, 0xd69906245565a910LL, 56 | 0xf40e35855771202aLL, 0x106aa07032bbd1b8LL, 57 | 0x19a4c116b8d2d0c8LL, 0x1e376c085141ab53LL, 58 | 0x2748774cdf8eeb99LL, 0x34b0bcb5e19b48a8LL, 59 | 0x391c0cb3c5c95a63LL, 0x4ed8aa4ae3418acbLL, 60 | 0x5b9cca4f7763e373LL, 0x682e6ff3d6b2b8a3LL, 61 | 0x748f82ee5defb2fcLL, 0x78a5636f43172f60LL, 62 | 0x84c87814a1f0ab72LL, 0x8cc702081a6439ecLL, 63 | 0x90befffa23631e28LL, 0xa4506cebde82bde9LL, 64 | 0xbef9a3f7b2c67915LL, 0xc67178f2e372532bLL, 65 | 0xca273eceea26619cLL, 0xd186b8c721c0c207LL, 66 | 0xeada7dd6cde0eb1eLL, 0xf57d4f7fee6ed178LL, 67 | 0x06f067aa72176fbaLL, 0x0a637dc5a2c898a6LL, 68 | 0x113f9804bef90daeLL, 0x1b710b35131c471bLL, 69 | 0x28db77f523047d84LL, 0x32caab7b40c72493LL, 70 | 0x3c9ebe0a15c9bebcLL, 0x431d67c49c100d4cLL, 71 | 0x4cc5d4becb3e42b6LL, 0x597f299cfc657e2aLL, 72 | 0x5fcb6fab3ad6faecLL, 0x6c44198c4a475817LL, 73 | }; 74 | 75 | static inline uint64_t load64(const uint8_t *x) 76 | { 77 | uint64_t r; 78 | 79 | r = *(x++); 80 | r = (r << 8) | *(x++); 81 | r = (r << 8) | *(x++); 82 | r = (r << 8) | *(x++); 83 | r = (r << 8) | *(x++); 84 | r = (r << 8) | *(x++); 85 | r = (r << 8) | *(x++); 86 | r = (r << 8) | *(x++); 87 | 88 | return r; 89 | } 90 | 91 | static inline void store64(uint8_t *x, uint64_t v) 92 | { 93 | x += 7; 94 | *(x--) = v; 95 | v >>= 8; 96 | *(x--) = v; 97 | v >>= 8; 98 | *(x--) = v; 99 | v >>= 8; 100 | *(x--) = v; 101 | v >>= 8; 102 | *(x--) = v; 103 | v >>= 8; 104 | *(x--) = v; 105 | v >>= 8; 106 | *(x--) = v; 107 | v >>= 8; 108 | *(x--) = v; 109 | } 110 | 111 | static inline uint64_t rot64(uint64_t x, int bits) 112 | { 113 | return (x >> bits) | (x << (64 - bits)); 114 | } 115 | 116 | static void 117 | sha512_block(struct sha512_state *s, const uint8_t *blk) 118 | { 119 | uint64_t w[16]; 120 | uint64_t a, b, c, d, e, f, g, h; 121 | int i; 122 | 123 | for (i = 0; i < 16; i++) { 124 | w[i] = load64(blk); 125 | blk += 8; 126 | } 127 | 128 | /* Load state */ 129 | a = s->h[0]; 130 | b = s->h[1]; 131 | c = s->h[2]; 132 | d = s->h[3]; 133 | e = s->h[4]; 134 | f = s->h[5]; 135 | g = s->h[6]; 136 | h = s->h[7]; 137 | 138 | for (i = 0; i < 80; i++) { 139 | /* Compute value of w[i + 16]. w[wrap(i)] is currently w[i] */ 140 | const uint64_t wi = w[i & 15]; 141 | const uint64_t wi15 = w[(i + 1) & 15]; 142 | const uint64_t wi2 = w[(i + 14) & 15]; 143 | const uint64_t wi7 = w[(i + 9) & 15]; 144 | const uint64_t s0 = 145 | rot64(wi15, 1) ^ rot64(wi15, 8) ^ (wi15 >> 7); 146 | const uint64_t s1 = 147 | rot64(wi2, 19) ^ rot64(wi2, 61) ^ (wi2 >> 6); 148 | 149 | /* Round calculations */ 150 | const uint64_t S0 = rot64(a, 28) ^ rot64(a, 34) ^ rot64(a, 39); 151 | const uint64_t S1 = rot64(e, 14) ^ rot64(e, 18) ^ rot64(e, 41); 152 | const uint64_t ch = (e & f) ^ ((~e) & g); 153 | const uint64_t temp1 = h + S1 + ch + round_k[i] + wi; 154 | const uint64_t maj = (a & b) ^ (a & c) ^ (b & c); 155 | const uint64_t temp2 = S0 + maj; 156 | 157 | /* Update round state */ 158 | h = g; 159 | g = f; 160 | f = e; 161 | e = d + temp1; 162 | d = c; 163 | c = b; 164 | b = a; 165 | a = temp1 + temp2; 166 | 167 | /* w[wrap(i)] becomes w[i + 16] */ 168 | w[i & 15] = wi + s0 + wi7 + s1; 169 | } 170 | 171 | /* Store state */ 172 | s->h[0] += a; 173 | s->h[1] += b; 174 | s->h[2] += c; 175 | s->h[3] += d; 176 | s->h[4] += e; 177 | s->h[5] += f; 178 | s->h[6] += g; 179 | s->h[7] += h; 180 | } 181 | 182 | void sha512_init(struct sha512_state *s) 183 | { 184 | memcpy(s->h, &sha512_initial_state, sizeof(s->h)); 185 | s->len = 0; 186 | } 187 | 188 | void sha512_add(struct sha512_state *s, const void *data, size_t len) 189 | { 190 | unsigned int partial = s->len & (SHA512_BLOCK_SIZE - 1); 191 | 192 | if (partial) { 193 | unsigned int cur = SHA512_BLOCK_SIZE - partial; 194 | 195 | if (cur > len) 196 | cur = len; 197 | 198 | memcpy(&s->partial[partial], data, cur); 199 | 200 | s->len += cur; 201 | data += cur; 202 | len -= cur; 203 | 204 | partial = s->len & (SHA512_BLOCK_SIZE - 1); 205 | if (!partial) 206 | sha512_block(s, s->partial); 207 | } 208 | 209 | while (len >= SHA512_BLOCK_SIZE) { 210 | sha512_block(s, data); 211 | 212 | s->len += SHA512_BLOCK_SIZE; 213 | data += SHA512_BLOCK_SIZE; 214 | len -= SHA512_BLOCK_SIZE; 215 | } 216 | 217 | if (!len) 218 | return; 219 | 220 | memcpy(s->partial, data, len); 221 | s->len += len; 222 | } 223 | 224 | void sha512_final(struct sha512_state *s, uint8_t *hash) 225 | { 226 | size_t last_size = s->len & (SHA512_BLOCK_SIZE - 1); 227 | unsigned int len = SHA512_HASH_SIZE; 228 | int i = 0; 229 | 230 | s->partial[last_size++] = 0x80; 231 | if (last_size < SHA512_BLOCK_SIZE) 232 | memset(&s->partial[last_size], 0, 233 | SHA512_BLOCK_SIZE - last_size); 234 | 235 | if (last_size > (SHA512_BLOCK_SIZE - 16)) { 236 | sha512_block(s, s->partial); 237 | memset(s->partial, 0, sizeof(s->partial)); 238 | } 239 | 240 | /* Note: we assume total_size fits in 61 bits */ 241 | store64(s->partial + SHA512_BLOCK_SIZE - 8, s->len << 3); 242 | sha512_block(s, s->partial); 243 | 244 | /* Read out whole words */ 245 | while (len >= 8) { 246 | store64(hash, s->h[i++]); 247 | hash += 8; 248 | len -= 8; 249 | } 250 | 251 | /* Read out bytes */ 252 | if (len) { 253 | uint8_t tmp[8]; 254 | 255 | store64(tmp, s->h[i]); 256 | memcpy(hash, tmp, len); 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /ed25519.c: -------------------------------------------------------------------------------- 1 | /* Edwards curve operations 2 | * Daniel Beer , 9 Jan 2014 3 | * 4 | * This file is in the public domain. 5 | */ 6 | 7 | #include "ed25519.h" 8 | 9 | /* Base point is (numbers wrapped): 10 | * 11 | * x = 151122213495354007725011514095885315114 12 | * 54012693041857206046113283949847762202 13 | * y = 463168356949264781694283940034751631413 14 | * 07993866256225615783033603165251855960 15 | * 16 | * y is derived by transforming the original Montgomery base (u=9). x 17 | * is the corresponding positive coordinate for the new curve equation. 18 | * t is x*y. 19 | */ 20 | const struct ed25519_pt ed25519_base = { 21 | .x = { 22 | 0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 23 | 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69, 24 | 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 25 | 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21 26 | }, 27 | .y = { 28 | 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 29 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 30 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 31 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 32 | }, 33 | .t = { 34 | 0xa3, 0xdd, 0xb7, 0xa5, 0xb3, 0x8a, 0xde, 0x6d, 35 | 0xf5, 0x52, 0x51, 0x77, 0x80, 0x9f, 0xf0, 0x20, 36 | 0x7d, 0xe3, 0xab, 0x64, 0x8e, 0x4e, 0xea, 0x66, 37 | 0x65, 0x76, 0x8b, 0xd7, 0x0f, 0x5f, 0x87, 0x67 38 | }, 39 | .z = {1, 0} 40 | }; 41 | 42 | static const struct ed25519_pt ed25519_neutral = { 43 | .x = {0}, 44 | .y = {1, 0}, 45 | .t = {0}, 46 | .z = {1, 0} 47 | }; 48 | 49 | /* Conversion to and from projective coordinates */ 50 | void ed25519_project(struct ed25519_pt *p, 51 | const uint8_t *x, const uint8_t *y) 52 | { 53 | f25519_copy(p->x, x); 54 | f25519_copy(p->y, y); 55 | f25519_load(p->z, 1); 56 | f25519_mul__distinct(p->t, x, y); 57 | } 58 | 59 | void ed25519_unproject(uint8_t *x, uint8_t *y, 60 | const struct ed25519_pt *p) 61 | { 62 | uint8_t z1[F25519_SIZE]; 63 | 64 | f25519_inv__distinct(z1, p->z); 65 | f25519_mul__distinct(x, p->x, z1); 66 | f25519_mul__distinct(y, p->y, z1); 67 | 68 | f25519_normalize(x); 69 | f25519_normalize(y); 70 | } 71 | 72 | /* Compress/uncompress points. We compress points by storing the x 73 | * coordinate and the parity of the y coordinate. 74 | * 75 | * Rearranging the curve equation, we obtain explicit formulae for the 76 | * coordinates: 77 | * 78 | * x = sqrt((y^2-1) / (1+dy^2)) 79 | * y = sqrt((x^2+1) / (1-dx^2)) 80 | * 81 | * Where d = (-121665/121666), or: 82 | * 83 | * d = 370957059346694393431380835087545651895 84 | * 42113879843219016388785533085940283555 85 | */ 86 | 87 | static const uint8_t ed25519_d[F25519_SIZE] = { 88 | 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, 89 | 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00, 90 | 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, 91 | 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52 92 | }; 93 | 94 | void ed25519_pack(uint8_t *c, const uint8_t *x, const uint8_t *y) 95 | { 96 | uint8_t tmp[F25519_SIZE]; 97 | uint8_t parity; 98 | 99 | f25519_copy(tmp, x); 100 | f25519_normalize(tmp); 101 | parity = (tmp[0] & 1) << 7; 102 | 103 | f25519_copy(c, y); 104 | f25519_normalize(c); 105 | c[31] |= parity; 106 | } 107 | 108 | uint8_t ed25519_try_unpack(uint8_t *x, uint8_t *y, const uint8_t *comp) 109 | { 110 | const int parity = comp[31] >> 7; 111 | uint8_t a[F25519_SIZE]; 112 | uint8_t b[F25519_SIZE]; 113 | uint8_t c[F25519_SIZE]; 114 | 115 | /* Unpack y */ 116 | f25519_copy(y, comp); 117 | y[31] &= 127; 118 | 119 | /* Compute c = y^2 */ 120 | f25519_mul__distinct(c, y, y); 121 | 122 | /* Compute b = (1+dy^2)^-1 */ 123 | f25519_mul__distinct(b, c, ed25519_d); 124 | f25519_add(a, b, f25519_one); 125 | f25519_inv__distinct(b, a); 126 | 127 | /* Compute a = y^2-1 */ 128 | f25519_sub(a, c, f25519_one); 129 | 130 | /* Compute c = a*b = (y^2-1)/(1-dy^2) */ 131 | f25519_mul__distinct(c, a, b); 132 | 133 | /* Compute a, b = +/-sqrt(c), if c is square */ 134 | f25519_sqrt(a, c); 135 | f25519_neg(b, a); 136 | 137 | /* Select one of them, based on the compressed parity bit */ 138 | f25519_select(x, a, b, (a[0] ^ parity) & 1); 139 | 140 | /* Verify that x^2 = c */ 141 | f25519_mul__distinct(a, x, x); 142 | f25519_normalize(a); 143 | f25519_normalize(c); 144 | 145 | return f25519_eq(a, c); 146 | } 147 | 148 | /* k = 2d */ 149 | static const uint8_t ed25519_k[F25519_SIZE] = { 150 | 0x59, 0xf1, 0xb2, 0x26, 0x94, 0x9b, 0xd6, 0xeb, 151 | 0x56, 0xb1, 0x83, 0x82, 0x9a, 0x14, 0xe0, 0x00, 152 | 0x30, 0xd1, 0xf3, 0xee, 0xf2, 0x80, 0x8e, 0x19, 153 | 0xe7, 0xfc, 0xdf, 0x56, 0xdc, 0xd9, 0x06, 0x24 154 | }; 155 | 156 | void ed25519_add(struct ed25519_pt *r, 157 | const struct ed25519_pt *p1, const struct ed25519_pt *p2) 158 | { 159 | /* Explicit formulas database: add-2008-hwcd-3 160 | * 161 | * source 2008 Hisil--Wong--Carter--Dawson, 162 | * http://eprint.iacr.org/2008/522, Section 3.1 163 | * appliesto extended-1 164 | * parameter k 165 | * assume k = 2 d 166 | * compute A = (Y1-X1)(Y2-X2) 167 | * compute B = (Y1+X1)(Y2+X2) 168 | * compute C = T1 k T2 169 | * compute D = Z1 2 Z2 170 | * compute E = B - A 171 | * compute F = D - C 172 | * compute G = D + C 173 | * compute H = B + A 174 | * compute X3 = E F 175 | * compute Y3 = G H 176 | * compute T3 = E H 177 | * compute Z3 = F G 178 | */ 179 | uint8_t a[F25519_SIZE]; 180 | uint8_t b[F25519_SIZE]; 181 | uint8_t c[F25519_SIZE]; 182 | uint8_t d[F25519_SIZE]; 183 | uint8_t e[F25519_SIZE]; 184 | uint8_t f[F25519_SIZE]; 185 | uint8_t g[F25519_SIZE]; 186 | uint8_t h[F25519_SIZE]; 187 | 188 | /* A = (Y1-X1)(Y2-X2) */ 189 | f25519_sub(c, p1->y, p1->x); 190 | f25519_sub(d, p2->y, p2->x); 191 | f25519_mul__distinct(a, c, d); 192 | 193 | /* B = (Y1+X1)(Y2+X2) */ 194 | f25519_add(c, p1->y, p1->x); 195 | f25519_add(d, p2->y, p2->x); 196 | f25519_mul__distinct(b, c, d); 197 | 198 | /* C = T1 k T2 */ 199 | f25519_mul__distinct(d, p1->t, p2->t); 200 | f25519_mul__distinct(c, d, ed25519_k); 201 | 202 | /* D = Z1 2 Z2 */ 203 | f25519_mul__distinct(d, p1->z, p2->z); 204 | f25519_add(d, d, d); 205 | 206 | /* E = B - A */ 207 | f25519_sub(e, b, a); 208 | 209 | /* F = D - C */ 210 | f25519_sub(f, d, c); 211 | 212 | /* G = D + C */ 213 | f25519_add(g, d, c); 214 | 215 | /* H = B + A */ 216 | f25519_add(h, b, a); 217 | 218 | /* X3 = E F */ 219 | f25519_mul__distinct(r->x, e, f); 220 | 221 | /* Y3 = G H */ 222 | f25519_mul__distinct(r->y, g, h); 223 | 224 | /* T3 = E H */ 225 | f25519_mul__distinct(r->t, e, h); 226 | 227 | /* Z3 = F G */ 228 | f25519_mul__distinct(r->z, f, g); 229 | } 230 | 231 | static void ed25519_double(struct ed25519_pt *r, const struct ed25519_pt *p) 232 | { 233 | /* Explicit formulas database: dbl-2008-hwcd 234 | * 235 | * source 2008 Hisil--Wong--Carter--Dawson, 236 | * http://eprint.iacr.org/2008/522, Section 3.3 237 | * compute A = X1^2 238 | * compute B = Y1^2 239 | * compute C = 2 Z1^2 240 | * compute D = a A 241 | * compute E = (X1+Y1)^2-A-B 242 | * compute G = D + B 243 | * compute F = G - C 244 | * compute H = D - B 245 | * compute X3 = E F 246 | * compute Y3 = G H 247 | * compute T3 = E H 248 | * compute Z3 = F G 249 | */ 250 | uint8_t a[F25519_SIZE]; 251 | uint8_t b[F25519_SIZE]; 252 | uint8_t c[F25519_SIZE]; 253 | uint8_t e[F25519_SIZE]; 254 | uint8_t f[F25519_SIZE]; 255 | uint8_t g[F25519_SIZE]; 256 | uint8_t h[F25519_SIZE]; 257 | 258 | /* A = X1^2 */ 259 | f25519_mul__distinct(a, p->x, p->x); 260 | 261 | /* B = Y1^2 */ 262 | f25519_mul__distinct(b, p->y, p->y); 263 | 264 | /* C = 2 Z1^2 */ 265 | f25519_mul__distinct(c, p->z, p->z); 266 | f25519_add(c, c, c); 267 | 268 | /* D = a A (alter sign) */ 269 | /* E = (X1+Y1)^2-A-B */ 270 | f25519_add(f, p->x, p->y); 271 | f25519_mul__distinct(e, f, f); 272 | f25519_sub(e, e, a); 273 | f25519_sub(e, e, b); 274 | 275 | /* G = D + B */ 276 | f25519_sub(g, b, a); 277 | 278 | /* F = G - C */ 279 | f25519_sub(f, g, c); 280 | 281 | /* H = D - B */ 282 | f25519_neg(h, b); 283 | f25519_sub(h, h, a); 284 | 285 | /* X3 = E F */ 286 | f25519_mul__distinct(r->x, e, f); 287 | 288 | /* Y3 = G H */ 289 | f25519_mul__distinct(r->y, g, h); 290 | 291 | /* T3 = E H */ 292 | f25519_mul__distinct(r->t, e, h); 293 | 294 | /* Z3 = F G */ 295 | f25519_mul__distinct(r->z, f, g); 296 | } 297 | 298 | void ed25519_smult(struct ed25519_pt *r_out, const struct ed25519_pt *p, 299 | const uint8_t *e) 300 | { 301 | struct ed25519_pt r; 302 | int i; 303 | 304 | ed25519_copy(&r, &ed25519_neutral); 305 | 306 | for (i = 255; i >= 0; i--) { 307 | const uint8_t bit = (e[i >> 3] >> (i & 7)) & 1; 308 | struct ed25519_pt s; 309 | 310 | ed25519_double(&r, &r); 311 | ed25519_add(&s, &r, p); 312 | 313 | f25519_select(r.x, r.x, s.x, bit); 314 | f25519_select(r.y, r.y, s.y, bit); 315 | f25519_select(r.z, r.z, s.z, bit); 316 | f25519_select(r.t, r.t, s.t, bit); 317 | } 318 | 319 | ed25519_copy(r_out, &r); 320 | } 321 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * usign - tiny signify replacement 3 | * 4 | * Copyright (C) 2015 Felix Fietkau 5 | * 6 | * Permission to use, copy, modify, and/or 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 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "base64.h" 31 | #include "edsign.h" 32 | #include "ed25519.h" 33 | 34 | struct pubkey { 35 | char pkalg[2]; 36 | uint8_t fingerprint[8]; 37 | uint8_t pubkey[EDSIGN_PUBLIC_KEY_SIZE]; 38 | }; 39 | 40 | struct seckey { 41 | char pkalg[2]; 42 | char kdfalg[2]; 43 | uint32_t kdfrounds; 44 | uint8_t salt[16]; 45 | uint8_t checksum[8]; 46 | uint8_t fingerprint[8]; 47 | uint8_t seckey[64]; 48 | }; 49 | 50 | struct sig { 51 | char pkalg[2]; 52 | uint8_t fingerprint[8]; 53 | uint8_t sig[EDSIGN_SIGNATURE_SIZE]; 54 | }; 55 | 56 | static const char *pubkeyfile; 57 | static const char *pubkeydir; 58 | static const char *sigfile; 59 | static const char *seckeyfile; 60 | static const char *comment; 61 | static bool quiet; 62 | static enum { 63 | CMD_NONE, 64 | CMD_VERIFY, 65 | CMD_SIGN, 66 | CMD_FINGERPRINT, 67 | CMD_GENERATE, 68 | } cmd = CMD_NONE; 69 | 70 | static uint64_t fingerprint_u64(const uint8_t *data) 71 | { 72 | uint64_t val = 0; 73 | 74 | #define ADD(_v) val = (val << 8) | _v 75 | ADD(data[0]); 76 | ADD(data[1]); 77 | ADD(data[2]); 78 | ADD(data[3]); 79 | ADD(data[4]); 80 | ADD(data[5]); 81 | ADD(data[6]); 82 | ADD(data[7]); 83 | #undef ADD 84 | 85 | return val; 86 | } 87 | 88 | static void 89 | file_error(const char *filename, bool _read) 90 | { 91 | if (!quiet || cmd != CMD_VERIFY) 92 | fprintf(stderr, "Cannot open file '%s' for %s\n", filename, 93 | _read ? "reading" : "writing"); 94 | exit(1); 95 | } 96 | 97 | static FILE * 98 | open_file(const char *filename, bool _read) 99 | { 100 | FILE *f; 101 | 102 | if (!strcmp(filename, "-")) 103 | return _read ? stdin : stdout; 104 | 105 | f = fopen(filename, _read ? "r" : "w"); 106 | if (!f) 107 | file_error(filename, _read); 108 | 109 | return f; 110 | } 111 | 112 | static void 113 | get_file(const char *filename, char *buf, int buflen) 114 | { 115 | FILE *f = open_file(filename, true); 116 | int len; 117 | 118 | while (1) { 119 | char *cur = fgets(buf, buflen, f); 120 | 121 | if (!cur) { 122 | fprintf(stderr, "Premature end of file\n"); 123 | exit(1); 124 | } 125 | 126 | if (strchr(buf, '\n')) 127 | break; 128 | } 129 | 130 | len = fread(buf, 1, buflen - 1, f); 131 | buf[len] = 0; 132 | fclose(f); 133 | } 134 | 135 | static bool 136 | get_base64_file(const char *file, void *dest, int size, void *buf, int buflen) 137 | { 138 | get_file(file, buf, buflen - 1); 139 | return b64_decode(buf, dest, size) == size; 140 | } 141 | 142 | static void write_file(const char *name, const uint8_t *fingerprint, 143 | const char *prefix, char *buf) 144 | { 145 | FILE *f; 146 | 147 | f = open_file(name, false); 148 | fputs("untrusted comment: ", f); 149 | if (comment) 150 | fputs(comment, f); 151 | else 152 | fprintf(f, "%s %016"PRIx64, prefix, 153 | fingerprint_u64(fingerprint)); 154 | fprintf(f, "\n%s\n", buf); 155 | fclose(f); 156 | } 157 | 158 | static int verify(const char *msgfile) 159 | { 160 | struct pubkey pkey; 161 | struct sig sig; 162 | struct edsign_verify_state vst; 163 | FILE *f; 164 | char buf[512]; 165 | 166 | f = open_file(msgfile, true); 167 | if (!f) { 168 | fprintf(stderr, "Cannot open message file\n"); 169 | return 1; 170 | } 171 | 172 | if (!get_base64_file(sigfile, &sig, sizeof(sig), buf, sizeof(buf)) || 173 | memcmp(sig.pkalg, "Ed", 2) != 0) { 174 | fprintf(stderr, "Failed to decode signature\n"); 175 | fclose(f); 176 | return 1; 177 | } 178 | 179 | if (!pubkeyfile) { 180 | snprintf(buf, sizeof(buf), "%s/%016"PRIx64, pubkeydir, 181 | fingerprint_u64(sig.fingerprint)); 182 | pubkeyfile = buf; 183 | } 184 | 185 | if (!get_base64_file(pubkeyfile, &pkey, sizeof(pkey), buf, sizeof(buf)) || 186 | memcmp(pkey.pkalg, "Ed", 2) != 0) { 187 | fprintf(stderr, "Failed to decode public key\n"); 188 | fclose(f); 189 | return 1; 190 | } 191 | 192 | edsign_verify_init(&vst, sig.sig, pkey.pubkey); 193 | 194 | while (!feof(f)) { 195 | int len = fread(buf, 1, sizeof(buf), f); 196 | edsign_verify_add(&vst, buf, len); 197 | } 198 | fclose(f); 199 | 200 | if (!edsign_verify(&vst, sig.sig, pkey.pubkey)) { 201 | if (!quiet) 202 | fprintf(stderr, "verification failed\n"); 203 | return 1; 204 | } 205 | 206 | if (!quiet) 207 | fprintf(stderr, "OK\n"); 208 | return 0; 209 | } 210 | 211 | static int sign(const char *msgfile) 212 | { 213 | struct seckey skey; 214 | struct sig sig = { 215 | .pkalg = "Ed", 216 | }; 217 | struct stat st; 218 | char buf[512]; 219 | void *pubkey = buf; 220 | long mlen; 221 | void *m; 222 | int mfd; 223 | 224 | if (!get_base64_file(seckeyfile, &skey, sizeof(skey), buf, sizeof(buf)) || 225 | memcmp(skey.pkalg, "Ed", 2) != 0) { 226 | fprintf(stderr, "Failed to decode secret key\n"); 227 | return 1; 228 | } 229 | 230 | if (skey.kdfrounds) { 231 | fprintf(stderr, "Password protected secret keys are not supported\n"); 232 | return 1; 233 | } 234 | 235 | mfd = open(msgfile, O_RDONLY, 0); 236 | if (mfd < 0 || fstat(mfd, &st) < 0 || 237 | (m = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, mfd, 0)) == MAP_FAILED) { 238 | if (mfd >= 0) 239 | close(mfd); 240 | perror("Cannot open message file"); 241 | return 1; 242 | } 243 | mlen = st.st_size; 244 | 245 | memcpy(sig.fingerprint, skey.fingerprint, sizeof(sig.fingerprint)); 246 | edsign_sec_to_pub(pubkey, skey.seckey); 247 | edsign_sign(sig.sig, pubkey, skey.seckey, m, mlen); 248 | munmap(m, mlen); 249 | close(mfd); 250 | 251 | if (b64_encode(&sig, sizeof(sig), buf, sizeof(buf)) < 0) 252 | return 1; 253 | 254 | write_file(sigfile, sig.fingerprint, "signed by key", buf); 255 | 256 | return 0; 257 | } 258 | 259 | static int fingerprint(void) 260 | { 261 | struct seckey skey; 262 | struct pubkey pkey; 263 | struct sig sig; 264 | char buf[512]; 265 | uint8_t *fp; 266 | 267 | if (seckeyfile && 268 | get_base64_file(seckeyfile, &skey, sizeof(skey), buf, sizeof(buf))) 269 | fp = skey.fingerprint; 270 | else if (pubkeyfile && 271 | get_base64_file(pubkeyfile, &pkey, sizeof(pkey), buf, sizeof(buf))) 272 | fp = pkey.fingerprint; 273 | else if (sigfile && 274 | get_base64_file(sigfile, &sig, sizeof(sig), buf, sizeof(buf))) 275 | fp = sig.fingerprint; 276 | else 277 | return 1; 278 | 279 | fprintf(stdout, "%016"PRIx64"\n", fingerprint_u64(fp)); 280 | return 0; 281 | } 282 | 283 | static int generate(void) 284 | { 285 | struct seckey skey = { 286 | .pkalg = "Ed", 287 | .kdfalg = "BK", 288 | .kdfrounds = 0, 289 | }; 290 | struct pubkey pkey = { 291 | .pkalg = "Ed", 292 | }; 293 | struct sha512_state s; 294 | char buf[512]; 295 | FILE *f; 296 | 297 | f = fopen("/dev/urandom", "r"); 298 | if (!f) { 299 | fprintf(stderr, "Can't open /dev/urandom\n"); 300 | return 1; 301 | } 302 | 303 | if (fread(skey.fingerprint, sizeof(skey.fingerprint), 1, f) != 1 || 304 | fread(skey.seckey, EDSIGN_SECRET_KEY_SIZE, 1, f) != 1 || 305 | fread(skey.salt, sizeof(skey.salt), 1, f) != 1) { 306 | fprintf(stderr, "Can't read data from /dev/urandom\n"); 307 | fclose(f); 308 | return 1; 309 | } 310 | if (f) 311 | fclose(f); 312 | 313 | ed25519_prepare(skey.seckey); 314 | edsign_sec_to_pub(skey.seckey + 32, skey.seckey); 315 | 316 | sha512_init(&s); 317 | sha512_add(&s, skey.seckey, sizeof(skey.seckey)); 318 | memcpy(skey.checksum, sha512_final_get(&s), sizeof(skey.checksum)); 319 | 320 | if (b64_encode(&skey, sizeof(skey), buf, sizeof(buf)) < 0) 321 | return 1; 322 | 323 | write_file(seckeyfile, skey.fingerprint, "private key", buf); 324 | 325 | memcpy(pkey.fingerprint, skey.fingerprint, sizeof(pkey.fingerprint)); 326 | memcpy(pkey.pubkey, skey.seckey + 32, sizeof(pkey.pubkey)); 327 | 328 | if (b64_encode(&pkey, sizeof(pkey), buf, sizeof(buf)) < 0) 329 | return 1; 330 | 331 | write_file(pubkeyfile, pkey.fingerprint, "public key", buf); 332 | 333 | return 0; 334 | } 335 | 336 | static int usage(const char *cmd) 337 | { 338 | fprintf(stderr, 339 | "Usage: %s \n" 340 | "Commands:\n" 341 | " -V: verify (needs at least -m and -p|-P)\n" 342 | " -S: sign (needs at least -m and -s)\n" 343 | " -F: print key fingerprint of public/secret key or signature\n" 344 | " -G: generate a new keypair (needs at least -p and -s)\n" 345 | "Options:\n" 346 | " -c : add comment to keys\n" 347 | " -m : message file\n" 348 | " -p : public key file (verify/fingerprint only)\n" 349 | " -P : public key directory (verify only)\n" 350 | " -q: quiet (do not print verification result, use return code only)\n" 351 | " -s : secret key file (sign/fingerprint only)\n" 352 | " -x : signature file (defaults to .sig)\n" 353 | "\n", 354 | cmd); 355 | return 1; 356 | } 357 | 358 | static void set_cmd(const char *prog, int val) 359 | { 360 | if (cmd != CMD_NONE) 361 | exit(usage(prog)); 362 | 363 | cmd = val; 364 | } 365 | 366 | int main(int argc, char **argv) 367 | { 368 | const char *msgfile = NULL; 369 | int ch; 370 | 371 | while ((ch = getopt(argc, argv, "FGSVc:m:P:p:qs:x:")) != -1) { 372 | switch (ch) { 373 | case 'V': 374 | set_cmd(argv[0], CMD_VERIFY); 375 | break; 376 | case 'S': 377 | set_cmd(argv[0], CMD_SIGN); 378 | break; 379 | case 'F': 380 | set_cmd(argv[0], CMD_FINGERPRINT); 381 | break; 382 | case 'G': 383 | set_cmd(argv[0], CMD_GENERATE); 384 | break; 385 | case 'c': 386 | comment = optarg; 387 | break; 388 | case 'm': 389 | msgfile = optarg; 390 | break; 391 | case 'P': 392 | pubkeydir = optarg; 393 | break; 394 | case 'p': 395 | pubkeyfile = optarg; 396 | break; 397 | case 's': 398 | seckeyfile = optarg; 399 | break; 400 | case 'x': 401 | sigfile = optarg; 402 | break; 403 | case 'q': 404 | quiet = true; 405 | break; 406 | default: 407 | return usage(argv[0]); 408 | } 409 | } 410 | 411 | if (!sigfile && msgfile) { 412 | char *buf = alloca(strlen(msgfile) + 5); 413 | 414 | if (!strcmp(msgfile, "-")) { 415 | fprintf(stderr, "Need signature file when reading message from stdin\n"); 416 | return 1; 417 | } 418 | 419 | sprintf(buf, "%s.sig", msgfile); 420 | sigfile = buf; 421 | } 422 | 423 | switch (cmd) { 424 | case CMD_VERIFY: 425 | if ((!pubkeyfile && !pubkeydir) || !msgfile) 426 | return usage(argv[0]); 427 | return verify(msgfile); 428 | case CMD_SIGN: 429 | if (!seckeyfile || !msgfile || !sigfile) 430 | return usage(argv[0]); 431 | return sign(msgfile); 432 | case CMD_FINGERPRINT: 433 | if (!!seckeyfile + !!pubkeyfile + !!sigfile != 1) { 434 | fprintf(stderr, "Need one secret/public key or signature\n"); 435 | return usage(argv[0]); 436 | } 437 | return fingerprint(); 438 | case CMD_GENERATE: 439 | if (!seckeyfile || !pubkeyfile) 440 | return usage(argv[0]); 441 | return generate(); 442 | default: 443 | return usage(argv[0]); 444 | } 445 | } 446 | -------------------------------------------------------------------------------- /base64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * base64 - libubox base64 functions 3 | * 4 | * Copyright (C) 2015 Felix Fietkau 5 | * 6 | * Permission to use, copy, modify, and/or 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 | 19 | /* $OpenBSD: base64.c,v 1.7 2013/12/31 02:32:56 tedu Exp $ */ 20 | 21 | /* 22 | * Copyright (c) 1996 by Internet Software Consortium. 23 | * 24 | * Permission to use, copy, modify, and distribute this software for any 25 | * purpose with or without fee is hereby granted, provided that the above 26 | * copyright notice and this permission notice appear in all copies. 27 | * 28 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 29 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 30 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 31 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 32 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 33 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 34 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 35 | * SOFTWARE. 36 | */ 37 | 38 | /* 39 | * Portions Copyright (c) 1995 by International Business Machines, Inc. 40 | * 41 | * International Business Machines, Inc. (hereinafter called IBM) grants 42 | * permission under its copyrights to use, copy, modify, and distribute this 43 | * Software with or without fee, provided that the above copyright notice and 44 | * all paragraphs of this notice appear in all copies, and that the name of IBM 45 | * not be used in connection with the marketing of any product incorporating 46 | * the Software or modifications thereof, without specific, written prior 47 | * permission. 48 | * 49 | * To the extent it has a right to do so, IBM grants an immunity from suit 50 | * under its patents, if any, for the use, sale or manufacture of products to 51 | * the extent that such products are used for performing Domain Name System 52 | * dynamic updates in TCP/IP networks by means of the Software. No immunity is 53 | * granted for any product per se or for any other function of any product. 54 | * 55 | * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, 56 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 57 | * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, 58 | * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING 59 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN 60 | * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. 61 | */ 62 | 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include "base64.h" 69 | 70 | static const char Base64[] = 71 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 72 | static const char Pad64 = '='; 73 | 74 | /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) 75 | The following encoding technique is taken from RFC 1521 by Borenstein 76 | and Freed. It is reproduced here in a slightly edited form for 77 | convenience. 78 | 79 | A 65-character subset of US-ASCII is used, enabling 6 bits to be 80 | represented per printable character. (The extra 65th character, "=", 81 | is used to signify a special processing function.) 82 | 83 | The encoding process represents 24-bit groups of input bits as output 84 | strings of 4 encoded characters. Proceeding from left to right, a 85 | 24-bit input group is formed by concatenating 3 8-bit input groups. 86 | These 24 bits are then treated as 4 concatenated 6-bit groups, each 87 | of which is translated into a single digit in the base64 alphabet. 88 | 89 | Each 6-bit group is used as an index into an array of 64 printable 90 | characters. The character referenced by the index is placed in the 91 | output string. 92 | 93 | Table 1: The Base64 Alphabet 94 | 95 | Value Encoding Value Encoding Value Encoding Value Encoding 96 | 0 A 17 R 34 i 51 z 97 | 1 B 18 S 35 j 52 0 98 | 2 C 19 T 36 k 53 1 99 | 3 D 20 U 37 l 54 2 100 | 4 E 21 V 38 m 55 3 101 | 5 F 22 W 39 n 56 4 102 | 6 G 23 X 40 o 57 5 103 | 7 H 24 Y 41 p 58 6 104 | 8 I 25 Z 42 q 59 7 105 | 9 J 26 a 43 r 60 8 106 | 10 K 27 b 44 s 61 9 107 | 11 L 28 c 45 t 62 + 108 | 12 M 29 d 46 u 63 / 109 | 13 N 30 e 47 v 110 | 14 O 31 f 48 w (pad) = 111 | 15 P 32 g 49 x 112 | 16 Q 33 h 50 y 113 | 114 | Special processing is performed if fewer than 24 bits are available 115 | at the end of the data being encoded. A full encoding quantum is 116 | always completed at the end of a quantity. When fewer than 24 input 117 | bits are available in an input group, zero bits are added (on the 118 | right) to form an integral number of 6-bit groups. Padding at the 119 | end of the data is performed using the '=' character. 120 | 121 | Since all base64 input is an integral number of octets, only the 122 | ------------------------------------------------- 123 | following cases can arise: 124 | 125 | (1) the final quantum of encoding input is an integral 126 | multiple of 24 bits; here, the final unit of encoded 127 | output will be an integral multiple of 4 characters 128 | with no "=" padding, 129 | (2) the final quantum of encoding input is exactly 8 bits; 130 | here, the final unit of encoded output will be two 131 | characters followed by two "=" padding characters, or 132 | (3) the final quantum of encoding input is exactly 16 bits; 133 | here, the final unit of encoded output will be three 134 | characters followed by one "=" padding character. 135 | */ 136 | 137 | int b64_encode(const void *_src, size_t srclength, 138 | void *dest, size_t targsize) 139 | { 140 | const unsigned char *src = _src; 141 | char *target = dest; 142 | size_t datalength = 0; 143 | u_char input[3]; 144 | u_char output[4]; 145 | int i; 146 | 147 | while (2 < srclength) { 148 | input[0] = *src++; 149 | input[1] = *src++; 150 | input[2] = *src++; 151 | srclength -= 3; 152 | 153 | output[0] = input[0] >> 2; 154 | output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); 155 | output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); 156 | output[3] = input[2] & 0x3f; 157 | 158 | if (datalength + 4 > targsize) 159 | return (-1); 160 | target[datalength++] = Base64[output[0]]; 161 | target[datalength++] = Base64[output[1]]; 162 | target[datalength++] = Base64[output[2]]; 163 | target[datalength++] = Base64[output[3]]; 164 | } 165 | 166 | /* Now we worry about padding. */ 167 | if (0 != srclength) { 168 | /* Get what's left. */ 169 | input[0] = input[1] = input[2] = '\0'; 170 | for (i = 0; i < srclength; i++) 171 | input[i] = *src++; 172 | 173 | output[0] = input[0] >> 2; 174 | output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); 175 | output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); 176 | 177 | if (datalength + 4 > targsize) 178 | return (-1); 179 | target[datalength++] = Base64[output[0]]; 180 | target[datalength++] = Base64[output[1]]; 181 | if (srclength == 1) 182 | target[datalength++] = Pad64; 183 | else 184 | target[datalength++] = Base64[output[2]]; 185 | target[datalength++] = Pad64; 186 | } 187 | if (datalength >= targsize) 188 | return (-1); 189 | target[datalength] = '\0'; /* Returned value doesn't count \0. */ 190 | return (datalength); 191 | } 192 | 193 | /* skips all whitespace anywhere. 194 | converts characters, four at a time, starting at (or after) 195 | src from base - 64 numbers into three 8 bit bytes in the target area. 196 | it returns the number of data bytes stored at the target, or -1 on error. 197 | */ 198 | 199 | int b64_decode(const void *_src, void *dest, size_t targsize) 200 | { 201 | const char *src = _src; 202 | unsigned char *target = dest; 203 | int tarindex, state, ch; 204 | u_char nextbyte; 205 | char *pos; 206 | 207 | state = 0; 208 | tarindex = 0; 209 | 210 | while ((ch = (unsigned char)*src++) != '\0') { 211 | if (isspace(ch)) /* Skip whitespace anywhere. */ 212 | continue; 213 | 214 | if (ch == Pad64) 215 | break; 216 | 217 | pos = strchr(Base64, ch); 218 | if (pos == 0) /* A non-base64 character. */ 219 | return (-1); 220 | 221 | switch (state) { 222 | case 0: 223 | if (target) { 224 | if (tarindex >= targsize) 225 | return (-1); 226 | target[tarindex] = (pos - Base64) << 2; 227 | } 228 | state = 1; 229 | break; 230 | case 1: 231 | if (target) { 232 | if (tarindex >= targsize) 233 | return (-1); 234 | target[tarindex] |= (pos - Base64) >> 4; 235 | nextbyte = ((pos - Base64) & 0x0f) << 4; 236 | if (tarindex + 1 < targsize) 237 | target[tarindex+1] = nextbyte; 238 | else if (nextbyte) 239 | return (-1); 240 | } 241 | tarindex++; 242 | state = 2; 243 | break; 244 | case 2: 245 | if (target) { 246 | if (tarindex >= targsize) 247 | return (-1); 248 | target[tarindex] |= (pos - Base64) >> 2; 249 | nextbyte = ((pos - Base64) & 0x03) << 6; 250 | if (tarindex + 1 < targsize) 251 | target[tarindex+1] = nextbyte; 252 | else if (nextbyte) 253 | return (-1); 254 | } 255 | tarindex++; 256 | state = 3; 257 | break; 258 | case 3: 259 | if (target) { 260 | if (tarindex >= targsize) 261 | return (-1); 262 | target[tarindex] |= (pos - Base64); 263 | } 264 | tarindex++; 265 | state = 0; 266 | break; 267 | } 268 | } 269 | 270 | /* 271 | * We are done decoding Base-64 chars. Let's see if we ended 272 | * on a byte boundary, and/or with erroneous trailing characters. 273 | */ 274 | 275 | if (ch == Pad64) { /* We got a pad char. */ 276 | ch = (unsigned char)*src++; /* Skip it, get next. */ 277 | switch (state) { 278 | case 0: /* Invalid = in first position */ 279 | case 1: /* Invalid = in second position */ 280 | return (-1); 281 | 282 | case 2: /* Valid, means one byte of info */ 283 | /* Skip any number of spaces. */ 284 | for (; ch != '\0'; ch = (unsigned char)*src++) 285 | if (!isspace(ch)) 286 | break; 287 | /* Make sure there is another trailing = sign. */ 288 | if (ch != Pad64) 289 | return (-1); 290 | ch = (unsigned char)*src++; /* Skip the = */ 291 | /* Fall through to "single trailing =" case. */ 292 | /* FALLTHROUGH */ 293 | 294 | case 3: /* Valid, means two bytes of info */ 295 | /* 296 | * We know this char is an =. Is there anything but 297 | * whitespace after it? 298 | */ 299 | for (; ch != '\0'; ch = (unsigned char)*src++) 300 | if (!isspace(ch)) 301 | return (-1); 302 | 303 | /* 304 | * Now make sure for cases 2 and 3 that the "extra" 305 | * bits that slopped past the last full byte were 306 | * zeros. If we don't check them, they become a 307 | * subliminal channel. 308 | */ 309 | if (target && tarindex < targsize && 310 | target[tarindex] != 0) 311 | return (-1); 312 | } 313 | } else { 314 | /* 315 | * We ended by seeing the end of the string. Make sure we 316 | * have no partial bytes lying around. 317 | */ 318 | if (state != 0) 319 | return (-1); 320 | } 321 | 322 | /* Null-terminate if we have room left */ 323 | if (tarindex < targsize) 324 | target[tarindex] = 0; 325 | 326 | return (tarindex); 327 | } 328 | --------------------------------------------------------------------------------