123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- /* vim: set expandtab ts=4 sw=4: */
- /*
- * You may redistribute this program and/or modify it under the terms of
- * the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- #include "crypto/Sign.h"
- #include "crypto/sign/crypto_sign_ed25519.h"
- #include "crypto/sign/ge.h"
- #include "crypto/sign/sc.h"
- Linker_require("crypto/sign/fe_0.c")
- Linker_require("crypto/sign/fe_1.c")
- Linker_require("crypto/sign/fe_add.c")
- Linker_require("crypto/sign/fe_cmov.c")
- Linker_require("crypto/sign/fe_copy.c")
- Linker_require("crypto/sign/fe_frombytes.c")
- Linker_require("crypto/sign/fe_invert.c")
- Linker_require("crypto/sign/fe_isnegative.c")
- Linker_require("crypto/sign/fe_isnonzero.c")
- Linker_require("crypto/sign/fe_mul.c")
- Linker_require("crypto/sign/fe_neg.c")
- Linker_require("crypto/sign/fe_pow22523.c")
- Linker_require("crypto/sign/fe_sq.c")
- Linker_require("crypto/sign/fe_sq2.c")
- Linker_require("crypto/sign/fe_sub.c")
- Linker_require("crypto/sign/fe_tobytes.c")
- Linker_require("crypto/sign/ge_add.c")
- Linker_require("crypto/sign/ge_double_scalarmult.c")
- Linker_require("crypto/sign/ge_frombytes.c")
- Linker_require("crypto/sign/ge_madd.c")
- Linker_require("crypto/sign/ge_msub.c")
- Linker_require("crypto/sign/ge_p1p1_to_p2.c")
- Linker_require("crypto/sign/ge_p1p1_to_p3.c")
- Linker_require("crypto/sign/ge_p2_0.c")
- Linker_require("crypto/sign/ge_p2_dbl.c")
- Linker_require("crypto/sign/ge_p3_0.c")
- Linker_require("crypto/sign/ge_p3_dbl.c")
- Linker_require("crypto/sign/ge_p3_to_cached.c")
- Linker_require("crypto/sign/ge_p3_to_p2.c")
- Linker_require("crypto/sign/ge_p3_tobytes.c")
- Linker_require("crypto/sign/ge_precomp_0.c")
- Linker_require("crypto/sign/ge_scalarmult_base.c")
- Linker_require("crypto/sign/ge_sub.c")
- Linker_require("crypto/sign/ge_tobytes.c")
- Linker_require("crypto/sign/sc_muladd.c")
- Linker_require("crypto/sign/sc_reduce.c")
- Linker_require("crypto/sign/open.c")
- #include <sodium/crypto_hash_sha512.h>
- // This is fairly streight forward, we're taking a curve25519 private key and
- // interpreting it as an ed25519 key. This works in conjunction with the public
- // key converter Sign_publicSigningKeyToCurve25519() which is able to re-derive
- // the encryption key from a public signing key.
- void Sign_signingKeyPairFromCurve25519(uint8_t keypairOut[64], uint8_t secretCryptoKey[32])
- {
- Bits_memcpy(keypairOut, secretCryptoKey, 32);
- // The lower 3 bits are always cleared in both curve25519 and ed25519 keys before use
- // see: https://crypto.stackexchange.com/a/12614
- keypairOut[0] &= 248;
- // You will notice that ed25519 uses &= 63 (setting bit number 354 to zero) while
- // curve25519 scalarmult uses &= 127, allowing bit number 254 to be potentially 1,
- // this might look as though the keys are different but since the next line flags bit
- // number 254 always to 1, there is no difference here between the way curve25519
- // implementations and ed25519 implementations work.
- keypairOut[31] &= 63;
- // Bit number 254 is always set in both curve25519 and ed25519 keys before use
- // see: https://crypto.stackexchange.com/a/11818
- keypairOut[31] |= 64;
- // This is just doing the same thing as vanilla ed25519 crypto_sign_keypair()
- // computation with the exception that we don't hash the private key before
- // computation.
- ge_p3 A;
- ge_scalarmult_base(&A, keypairOut);
- ge_p3_tobytes(&keypairOut[32], &A);
- }
- void Sign_publicKeyFromKeyPair(uint8_t publicSigningKey[32], uint8_t keyPair[64])
- {
- Bits_memcpy(publicSigningKey, &keyPair[32], 32);
- }
- // This function is here because cjdns traditionally did not include signing, it only
- // has a key for encryption so when signing was implemented, in order not to break
- // everyone who has a cjdroute.conf file already, we needed to be able to convert
- // the encryption key to a signing key.
- // That in itself is fairly easy, and considered to be safe, but unfortunately nacl
- // and libsodium ed25519 implementations hash the private key before each use, making
- // it impossible to use our private key derived from a curve25519 encryption private key.
- //
- // The reason why nacl hashes the private key is to expand 32 bytes of entropy into 64
- // bytes, half of which is used as the actual signing key and half of which is used as
- // a secret random value which when combined with the hash of the message creates a
- // value r that is unpredictable and different for each message signed. It's important
- // to note that if r is the same for two different messages then there is a way for an
- // attacker to mathmatically derive the private key.
- //
- // What we do here instead is take the hash of the actual private key used to sign with
- // plus some random "belt and suspenders" bytes. Generally speaking, we should consider
- // that there is no more dissernable relationship between the public key and the sha512
- // of the private key than there is between the public key and the second half of the
- // same sha512 which produces the private key, but this is walking off of the beaten path
- // and throwing in a little bit of random each message should not make the situation any
- // worse.
- void Sign_signMsg(uint8_t keyPair[64], Message_t* msg, struct Random* rand)
- {
- // az is set to the secret key followed by another secret value
- // which since we don't have a secret seed in this algorithm is just the
- // hash of the secret key and 32 bytes of random
- uint8_t az[64];
- uint8_t r[64];
- ge_p3 R;
- uint8_t hram[64];
- // First we need to derive a unique random value, we'll do this by hashing the secret
- // key plus 32 bytes of random, whereas crypto_sign() achieves this by taking half of
- // the hash of the secret key that is input to it.
- Bits_memcpy(az, keyPair, 32);
- Random_bytes(rand, &az[32], 32);
- crypto_hash_sha512(az,az,64);
- // Ok, now az contains 64 bytes of unique random value, the upper 32 bytes needs to
- // be set to the actual secret key that we're going to use for signing.
- Bits_memcpy(az, keyPair, 32);
- // The reason for these numbers being masked off is explained above, but this is no
- // different from crypto_sign()
- az[0] &= 248;
- az[31] &= 63;
- az[31] |= 64;
- // hash message + secret number, this is the same as crypto_sign()
- // If there isn't enough space in the message, we abort the process
- Er_assert(Message_epush(msg, &az[32], 32));
- crypto_hash_sha512(r, Message_bytes(msg), Message_getLength(msg));
- // Replace secret number with public key, this is the same as crypto_sign()
- Bits_memcpy(Message_bytes(msg), &keyPair[32], 32);
- // Now we scalar multiply the hash of the message + unique secret and push that
- // to the message, nothing different from crypto_sign()
- sc_reduce(r);
- ge_scalarmult_base(&R,r);
- // If there isn't enough space in the message, we abort the process
- Er_assert(Message_eshift(msg, 32));
- ge_p3_tobytes(Message_bytes(msg),&R);
- // This final step is the same as crypto_sign()
- // Overwrite the public key which the verifier will replace in order to recompute
- // the hash.
- crypto_hash_sha512(hram, Message_bytes(msg), Message_getLength(msg));
- sc_reduce(hram);
- sc_muladd(&Message_bytes(msg)[32], hram, az, r);
- }
- // For verify, we're just using the normal sign_open() function, nothing special here.
- int Sign_verifyMsg(uint8_t publicSigningKey[32], Message_t* msg)
- {
- if (Message_getLength(msg) < 64) { return -1; }
- struct Allocator* alloc = Allocator_child(Message_getAlloc(msg));
- uint8_t* buff = Allocator_malloc(alloc, Message_getLength(msg));
- unsigned long long ml = Message_getLength(msg);
- int ret = crypto_sign_ed25519_open(buff, &ml, Message_bytes(msg), Message_getLength(msg), publicSigningKey);
- Allocator_free(alloc);
- if (ret) {
- return -1;
- }
- Er_assert(Message_epop(msg, NULL, 64));
- return 0;
- }
- // This is a copy of libsodium's implementation:
- // https://github.com/jedisct1/libsodium/blob/eae4add8de435a7fad08eab4f6e7cbfa9209a692/
- // src/libsodium/crypto_sign/ed25519/ref10/keypair.c#L45
- // Note that in newer versions Libsodium added a checks
- // * ge25519_has_small_order - refusing signatures made with weak public keys
- // * ge25519_is_on_main_subgroup - refusing signatures from keys on different subgroups
- // These additions are specific to Libsodium, they not in the original NACL ed25519
- // implementation, nor in tweetnacl.
- int Sign_publicSigningKeyToCurve25519(uint8_t curve25519keyOut[32], uint8_t publicSigningKey[32])
- {
- ge_p3 A;
- fe x;
- fe one_minus_y;
- if (ge_frombytes_negate_vartime(&A, publicSigningKey) != 0) {
- return -1;
- }
- fe_1(one_minus_y);
- fe_sub(one_minus_y, one_minus_y, A.Y);
- fe_invert(one_minus_y, one_minus_y);
- fe_1(x);
- fe_add(x, x, A.Y);
- fe_mul(x, x, one_minus_y);
- fe_tobytes(curve25519keyOut, x);
- return 0;
- }
|