/* 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 . */ #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 // 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; }