Example #1
0
/**
 * Get a shared secret.
 *
 * @param outputSecret an array to place the shared secret in.
 * @param myPrivateKey
 * @param herPublicKey
 * @param logger
 * @param passwordHash a 32 byte value known to both ends, this must be provably pseudorandom
 *                     the first 32 bytes of a sha256 output from hashing a password is ok,
 *                     whatever she happens to send me in the Auth field is NOT ok.
 *                     If this field is null, the secret will be generated without the password.
 */
static inline void getSharedSecret(uint8_t outputSecret[32],
                                   uint8_t myPrivateKey[32],
                                   uint8_t herPublicKey[32],
                                   uint8_t passwordHash[32],
                                   struct Log* logger)
{
    uint8_t tempBuff[64];
    crypto_scalarmult_curve25519(tempBuff, myPrivateKey, herPublicKey);
    if (passwordHash == NULL) {
        crypto_core_hsalsa20(outputSecret, keyHashNonce, tempBuff, keyHashSigma);
    } else {
        memcpy(&tempBuff[32], passwordHash, 32);
        crypto_hash_sha256(outputSecret, tempBuff, 64);
    }
    #ifdef Log_KEYS
        uint8_t myPublicKeyHex[65];
        printHexPubKey(myPublicKeyHex, myPrivateKey);
        uint8_t herPublicKeyHex[65];
        printHexKey(herPublicKeyHex, herPublicKey);
        uint8_t passwordHashHex[65];
        printHexKey(passwordHashHex, passwordHash);
        uint8_t outputSecretHex[65] = "NULL";
        printHexKey(outputSecretHex, outputSecret);
        Log_keys4(logger,
                  "Generated a shared secret:\n"
                  "     myPublicKey=%s\n"
                  "    herPublicKey=%s\n"
                  "    passwordHash=%s\n"
                  "    outputSecret=%s\n",
                  myPublicKeyHex, herPublicKeyHex, passwordHashHex, outputSecretHex);
    #endif
}
Example #2
0
struct CryptoAuth* CryptoAuth_new(struct Allocator* allocator,
                                  const uint8_t* privateKey,
                                  struct EventBase* eventBase,
                                  struct Log* logger,
                                  struct Random* rand)
{
    struct CryptoAuth_pvt* ca = Allocator_calloc(allocator, sizeof(struct CryptoAuth_pvt), 1);
    Identity_set(ca);
    ca->allocator = allocator;
    ca->eventBase = eventBase;
    ca->logger = logger;
    ca->pub.resetAfterInactivitySeconds = CryptoAuth_DEFAULT_RESET_AFTER_INACTIVITY_SECONDS;
    ca->rand = rand;

    if (privateKey != NULL) {
        Bits_memcpyConst(ca->privateKey, privateKey, 32);
    } else {
        Random_bytes(rand, ca->privateKey, 32);
    }
    crypto_scalarmult_curve25519_base(ca->pub.publicKey, ca->privateKey);

    if (Defined(Log_KEYS)) {
        uint8_t publicKeyHex[65];
        printHexKey(publicKeyHex, ca->pub.publicKey);
        uint8_t privateKeyHex[65];
        printHexKey(privateKeyHex, ca->privateKey);
        Log_keys(logger,
                  "Initialized CryptoAuth:\n    myPrivateKey=%s\n     myPublicKey=%s\n",
                  privateKeyHex,
                  publicKeyHex);
    }

    return &ca->pub;
}
Example #3
0
struct CryptoAuth* CryptoAuth_new(struct Allocator* allocator,
                                  const uint8_t* privateKey,
                                  struct event_base* eventBase,
                                  struct Log* logger)
{
    struct CryptoAuth_pvt* ca = allocator->calloc(sizeof(struct CryptoAuth_pvt), 1, allocator);
    ca->allocator = allocator;

    ca->passwords = allocator->calloc(sizeof(struct CryptoAuth_Auth), 256, allocator);
    ca->passwordCount = 0;
    ca->passwordCapacity = 256;
    ca->eventBase = eventBase;
    ca->logger = logger;
    ca->pub.resetAfterInactivitySeconds = CryptoAuth_DEFAULT_RESET_AFTER_INACTIVITY_SECONDS;

    if (privateKey != NULL) {
        Bits_memcpyConst(ca->privateKey, privateKey, 32);
        crypto_scalarmult_curve25519_base(ca->pub.publicKey, ca->privateKey);
    } else {
        crypto_box_curve25519xsalsa20poly1305_keypair(ca->pub.publicKey, ca->privateKey);
    }

    #ifdef Log_KEYS
        uint8_t publicKeyHex[65];
        printHexKey(publicKeyHex, ca->pub.publicKey);
        uint8_t privateKeyHex[65];
        printHexKey(privateKeyHex, ca->privateKey);
        Log_keys(logger,
                  "Initialized CryptoAuth:\n    myPrivateKey=%s\n     myPublicKey=%s\n",
                  privateKeyHex,
                  publicKeyHex);
    #endif

    return &ca->pub;
}
Example #4
0
static inline void printHexPubKey(uint8_t output[65], uint8_t privateKey[32])
{
    if (privateKey) {
        uint8_t publicKey[32];
        crypto_scalarmult_curve25519_base(publicKey, privateKey);
        printHexKey(output, publicKey);
    } else {
        printHexKey(output, NULL);
    }
}
Example #5
0
/**
 * Get a shared secret.
 *
 * @param outputSecret an array to place the shared secret in.
 * @param myPrivateKey
 * @param herPublicKey
 * @param logger
 * @param passwordHash a 32 byte value known to both ends, this must be provably pseudorandom
 *                     the first 32 bytes of a sha256 output from hashing a password is ok,
 *                     whatever she happens to send me in the Auth field is NOT ok.
 *                     If this field is null, the secret will be generated without the password.
 */
static inline void getSharedSecret(uint8_t outputSecret[32],
                                   uint8_t myPrivateKey[32],
                                   uint8_t herPublicKey[32],
                                   uint8_t passwordHash[32],
                                   struct Log* logger)
{
    if (passwordHash == NULL) {
        crypto_box_curve25519xsalsa20poly1305_beforenm(outputSecret, herPublicKey, myPrivateKey);
    } else {
        union {
            struct {
                uint8_t key[32];
                uint8_t passwd[32];
            } components;
            uint8_t bytes[64];
        } buff;

        crypto_scalarmult_curve25519(buff.components.key, myPrivateKey, herPublicKey);
        Bits_memcpyConst(buff.components.passwd, passwordHash, 32);
        crypto_hash_sha256(outputSecret, buff.bytes, 64);
    }
    #ifdef Log_KEYS
        uint8_t myPublicKeyHex[65];
        printHexPubKey(myPublicKeyHex, myPrivateKey);
        uint8_t herPublicKeyHex[65];
        printHexKey(herPublicKeyHex, herPublicKey);
        uint8_t passwordHashHex[65];
        printHexKey(passwordHashHex, passwordHash);
        uint8_t outputSecretHex[65] = "NULL";
        printHexKey(outputSecretHex, outputSecret);
        Log_keys(logger,
                  "Generated a shared secret:\n"
                  "     myPublicKey=%s\n"
                  "    herPublicKey=%s\n"
                  "    passwordHash=%s\n"
                  "    outputSecret=%s\n",
                  myPublicKeyHex, herPublicKeyHex, passwordHashHex, outputSecretHex);
    #endif
}
Example #6
0
static uint8_t decryptHandshake(struct Wrapper* wrapper,
                                const uint32_t nonce,
                                struct Message* message,
                                union Headers_CryptoAuth* header)
{
    if (message->length < sizeof(union Headers_CryptoAuth)) {
        Log_debug(wrapper->context->logger, "Dropped runt packet\n");
        return Error_UNDERSIZE_MESSAGE;
    }

    // handshake
    // nextNonce 0: recieving hello.
    // nextNonce 1: recieving key, we sent hello.
    // nextNonce 2: recieving first data packet or duplicate hello.
    // nextNonce 3: recieving first data packet.
    // nextNonce >3: handshake complete

    if (wrapper->nextNonce < 2 && nonce == UINT32_MAX && !wrapper->requireAuth) {
        // Reset without knowing key is allowed until state reaches 2.
        // this is because we don't know that the other end knows our key until we
        // have received a valid packet from them.
        // We can't allow the upper layer to see this message because it's not authenticated.
        if (!knowHerKey(wrapper)) {
            memcpy(wrapper->herPerminentPubKey, header->handshake.publicKey, 32);
        }
        Message_shift(message, -Headers_CryptoAuth_SIZE);
        message->length = 0;
        wrapper->nextNonce = 0;
        wrapper->user = NULL;
        // Send an empty response (to initiate the connection).
        encryptHandshake(message, wrapper);
        return Error_NONE;
    }

    void* user = NULL;
    uint8_t passwordHashStore[32];
    uint8_t* passwordHash = tryAuth(header, passwordHashStore, wrapper, &user);
    if (wrapper->requireAuth && !user) {
        Log_debug(wrapper->context->logger,
                  "Dropping message because auth was not given and is required.\n");
        return Error_AUTHENTICATION;
    }
    if (passwordHash == NULL && header->handshake.auth.challenge.type != 0) {
        Log_debug(wrapper->context->logger,
                  "Dropping message because it contans an authenticator which is unrecognized.\n");
        return Error_AUTHENTICATION;
    }

    // What the nextNonce will become if this packet is valid.
    uint32_t nextNonce;

    // The secret for decrypting this message.
    uint8_t sharedSecret[32];

    uint8_t* herPermKey = NULL;
    if (nonce < 2) {
        if (nonce == 0) {
            Log_debug1(wrapper->context->logger,
                       "Received a hello packet, using auth: %d\n",
                       (passwordHash != NULL));
        } else {
            Log_debug(wrapper->context->logger, "Received a repeat hello packet\n");
        }

        // Decrypt message with perminent keys.
        if (!knowHerKey(wrapper) || wrapper->nextNonce == 0) {
            herPermKey = header->handshake.publicKey;
            #ifdef Log_DEBUG
                if (Bits_isZero(header->handshake.publicKey, 32)) {
                    Log_debug(wrapper->context->logger, "Node sent public key of ZERO!\n");
                }
            #endif
        } else {
            herPermKey = wrapper->herPerminentPubKey;
            if (memcmp(header->handshake.publicKey, herPermKey, 32)) {
                Log_debug(wrapper->context->logger, "Packet contains different perminent key.\n");
                return Error_AUTHENTICATION;
            }
        }

        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        herPermKey,
                        passwordHash,
                        wrapper->context->logger);
        nextNonce = 2;
    } else {
        if (nonce == 2) {
            Log_debug(wrapper->context->logger, "Received a key packet\n");
        } else if (nonce == 3) {
            Log_debug(wrapper->context->logger, "Received a repeat key packet\n");
        } else {
            Log_debug1(wrapper->context->logger,
                       "Received a packet of unknown type! nonce=%u\n", nonce);
        }
        if (memcmp(header->handshake.publicKey, wrapper->herPerminentPubKey, 32)) {
            Log_debug(wrapper->context->logger, "Packet contains different perminent key.\n");
            return Error_AUTHENTICATION;
        }
        // We sent the hello, this is a key
        getSharedSecret(sharedSecret,
                        wrapper->secret,
                        wrapper->herPerminentPubKey,
                        passwordHash,
                        wrapper->context->logger);
        nextNonce = 4;
    }

    // Shift it on top of the authenticator before the encrypted public key
    Message_shift(message, 48 - Headers_CryptoAuth_SIZE);

    Log_debug1(wrapper->context->logger, "Message length: %u\n", message->length);
    #ifdef Log_KEYS
        uint8_t sharedSecretHex[65];
        printHexKey(sharedSecretHex, sharedSecret);
        uint8_t nonceHex[49];
        Hex_encode(nonceHex, 49, header->handshake.nonce, 24);
        uint8_t cipherHex[65];
        printHexKey(cipherHex, message->bytes);
        Log_keys3(wrapper->context->logger,
                  "Decrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    #endif

    // Decrypt her temp public key and the message.
    if (decryptRndNonce(header->handshake.nonce, message, sharedSecret) != 0) {
        // just in case
        memset(header, 0, Headers_CryptoAuth_SIZE);
        Log_debug(wrapper->context->logger,
                  "Dropped message because authenticated decryption failed.\n");
        return Error_AUTHENTICATION;
    }

    wrapper->user = user;
    memcpy(wrapper->tempKey, header->handshake.encryptedTempKey, 32);

    #ifdef Log_DEBUG
        assert(!Bits_isZero(header->handshake.encryptedTempKey, 32));
    #endif
    #ifdef Log_KEYS
        uint8_t tempKeyHex[65];
        Hex_encode(tempKeyHex, 65, wrapper->tempKey, 32);
        Log_keys1(wrapper->context->logger,
                  "Unwrapping temp public key:\n"
                  "    %s\n",
                  tempKeyHex);
    #endif

    Message_shift(message, -32);
    wrapper->nextNonce = nextNonce;
    if (nextNonce == 2) {
        wrapper->isInitiator = false;
    }
    if (herPermKey && herPermKey != wrapper->herPerminentPubKey) {
        memcpy(wrapper->herPerminentPubKey, herPermKey, 32);
    }

    // If this is a handshake which was initiated in reverse because we
    // didn't know the other node's key, now send what we were going to send.
    if (wrapper->hasBufferedMessage && message->length == 0) {
        Log_debug(wrapper->context->logger, "Sending buffered message.\n");
        sendMessage(wrapper->bufferedMessage, &wrapper->externalInterface);
        wrapper->hasBufferedMessage = false;
        return Error_NONE;
    } else if (wrapper->hasBufferedMessage) {
        Log_debug(wrapper->context->logger, "There is a buffered message.\n");
    }

    memset(&wrapper->replayProtector, 0, sizeof(struct ReplayProtector));

    setRequiredPadding(wrapper);
    return callReceivedMessage(wrapper, message);
}
Example #7
0
static uint8_t encryptHandshake(struct Message* message, struct Wrapper* wrapper)
{
    assert(message->padding >= sizeof(union Headers_CryptoAuth) || !"not enough padding");

    Message_shift(message, sizeof(union Headers_CryptoAuth));

    union Headers_CryptoAuth* header = (union Headers_CryptoAuth*) message->bytes;

    // garbage the auth field to frustrate DPI and set the nonce (next 24 bytes after the auth)
    randombytes((uint8_t*) &header->handshake.auth, sizeof(union Headers_AuthChallenge) + 24);
    memcpy(&header->handshake.publicKey, wrapper->context->publicKey, 32);

    if (!knowHerKey(wrapper)) {
        return genReverseHandshake(message, wrapper, header);
    }

    // Password auth
    uint8_t* passwordHash = NULL;
    if (wrapper->password != NULL) {
        struct Auth auth;
        passwordHash = hashPassword(&auth, wrapper->password, wrapper->authType);
        memcpy(header->handshake.auth.bytes, &auth.challenge, sizeof(union Headers_AuthChallenge));
    }
    header->handshake.auth.challenge.type = wrapper->authType;

    Headers_setPacketAuthRequired(&header->handshake.auth, wrapper->authenticatePackets);

    // set the session state
    uint32_t sessionState_be = Endian_hostToBigEndian32(wrapper->nextNonce);
    header->nonce = sessionState_be;

    if (wrapper->nextNonce == 0 || wrapper->nextNonce == 2) {
        // If we're sending a hello or a key
        crypto_box_curve25519xsalsa20poly1305_keypair(header->handshake.encryptedTempKey,
                                                      wrapper->secret);
        if (wrapper->nextNonce == 0) {
            memcpy(wrapper->tempKey, header->handshake.encryptedTempKey, 32);
        }
        #ifdef Log_DEBUG
            assert(!Bits_isZero(header->handshake.encryptedTempKey, 32));
            assert(!Bits_isZero(wrapper->secret, 32));
        #endif
    } else if (wrapper->nextNonce == 3) {
        // Dupe key
        // If nextNonce is 1 then we have our pubkey stored in wrapper->tempKey,
        // If nextNonce is 3 we need to recalculate it each time
        // because tempKey the final secret.
        crypto_scalarmult_curve25519_base(header->handshake.encryptedTempKey,
                                          wrapper->secret);
    } else {
        // Dupe hello
        // wrapper->nextNonce == 1
        // Our public key is cached in wrapper->tempKey so lets copy it out.
        memcpy(header->handshake.encryptedTempKey, wrapper->tempKey, 32);
    }

    uint8_t sharedSecret[32];
    if (wrapper->nextNonce < 2) {
        if (wrapper->nextNonce == 0) {
            Log_debug(wrapper->context->logger, "Sending hello packet\n");
        } else {
            Log_debug(wrapper->context->logger, "Sending repeat hello packet\n");
        }
        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        wrapper->herPerminentPubKey,
                        passwordHash,
                        wrapper->context->logger);
        wrapper->isInitiator = true;
        wrapper->nextNonce = 1;
        #ifdef Log_DEBUG
            assert(!Bits_isZero(header->handshake.encryptedTempKey, 32));
            uint8_t myTempPubKey[32];
            crypto_scalarmult_curve25519_base(myTempPubKey, wrapper->secret);
            assert(!memcmp(header->handshake.encryptedTempKey, myTempPubKey, 32));
        #endif
        #ifdef Log_KEYS
            uint8_t tempKeyHex[65];
            Hex_encode(tempKeyHex, 65, header->handshake.encryptedTempKey, 32);
            Log_keys1(wrapper->context->logger,
                      "Wrapping temp public key:\n"
                      "    %s\n",
                      tempKeyHex);
        #endif
    } else {
        if (wrapper->nextNonce == 2) {
            Log_debug(wrapper->context->logger, "Sending key packet\n");
        } else {
            Log_debug(wrapper->context->logger, "Sending repeat key packet\n");
        }
        // Handshake2 wrapper->tempKey holds her public temp key.
        // it was put there by receiveMessage()
        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        wrapper->tempKey,
                        passwordHash,
                        wrapper->context->logger);
        wrapper->nextNonce = 3;

        #ifdef Log_KEYS
            uint8_t tempKeyHex[65];
            Hex_encode(tempKeyHex, 65, wrapper->tempKey, 32);
            Log_keys1(wrapper->context->logger,
                      "Using their temp public key:\n"
                      "    %s\n",
                      tempKeyHex);
        #endif
    }

    // Shift message over the encryptedTempKey field.
    Message_shift(message, 32 - Headers_CryptoAuth_SIZE);

    encryptRndNonce(header->handshake.nonce, message, sharedSecret);

    Log_debug1(wrapper->context->logger, "Message length: %u\n", message->length);
    #ifdef Log_KEYS
        uint8_t sharedSecretHex[65];
        printHexKey(sharedSecretHex, sharedSecret);
        uint8_t nonceHex[49];
        Hex_encode(nonceHex, 49, header->handshake.nonce, 24);
        uint8_t cipherHex[65];
        printHexKey(cipherHex, message->bytes);
        Log_keys3(wrapper->context->logger,
                  "Encrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    #endif
    #ifdef Log_DEBUG
        assert(!Bits_isZero(header->handshake.encryptedTempKey, 32));
    #endif

    // Shift it back -- encryptRndNonce adds 16 bytes of authenticator.
    Message_shift(message, Headers_CryptoAuth_SIZE - 32 - 16);

    return wrapper->wrappedInterface->sendMessage(message, wrapper->wrappedInterface);
}
Example #8
0
static uint8_t decryptHandshake(struct CryptoAuth_Wrapper* wrapper,
                                const uint32_t nonce,
                                struct Message* message,
                                union Headers_CryptoAuth* header)
{
    if (message->length < Headers_CryptoAuth_SIZE) {
        cryptoAuthDebug0(wrapper, "DROP runt");
        return Error_UNDERSIZE_MESSAGE;
    }

    // handshake
    // nextNonce 0: recieving hello.
    // nextNonce 1: recieving key, we sent hello.
    // nextNonce 2: recieving first data packet or duplicate hello.
    // nextNonce 3: recieving first data packet.
    // nextNonce >3: handshake complete

    if (knowHerKey(wrapper)) {
        if (Bits_memcmp(wrapper->herPerminentPubKey, header->handshake.publicKey, 32)) {
            cryptoAuthDebug0(wrapper, "DROP a packet with different public key than this session");
            return Error_AUTHENTICATION;
        }
    } else if (!Bits_isZero(wrapper->herIp6, 16)) {
        uint8_t calculatedIp6[16];
        AddressCalc_addressForPublicKey(calculatedIp6, header->handshake.publicKey);
        if (Bits_memcmp(wrapper->herIp6, calculatedIp6, 16)) {
            cryptoAuthDebug0(wrapper, "DROP packet with public key not matching ip6 for session");
            return Error_AUTHENTICATION;
        }
    }

    if (wrapper->nextNonce < 2 && nonce == UINT32_MAX && !wrapper->requireAuth) {
        // Reset without knowing key is allowed until state reaches 2.
        // this is because we don't know that the other end knows our key until we
        // have received a valid packet from them.
        // We can't allow the upper layer to see this message because it's not authenticated.
        if (!knowHerKey(wrapper)) {
            Bits_memcpyConst(wrapper->herPerminentPubKey, header->handshake.publicKey, 32);
        }
        Message_shift(message, -Headers_CryptoAuth_SIZE, NULL);
        message->length = 0;
        reset(wrapper);
        wrapper->user = NULL;
        cryptoAuthDebug0(wrapper, "Got a connect-to-me message, sending a hello");
        // Send an empty response (to initiate the connection).
        encryptHandshake(message, wrapper, 1);
        return Error_NONE;
    }

    String* user = NULL;
    uint8_t passwordHashStore[32];
    uint8_t* passwordHash = tryAuth(header, passwordHashStore, wrapper, &user);
    if (wrapper->requireAuth && !user) {
        cryptoAuthDebug0(wrapper, "DROP message because auth was not given");
        return Error_AUTHENTICATION;
    }
    if (passwordHash == NULL && header->handshake.auth.challenge.type != 0) {
        cryptoAuthDebug0(wrapper, "DROP message with unrecognized authenticator");
        return Error_AUTHENTICATION;
    }

    // What the nextNonce will become if this packet is valid.
    uint32_t nextNonce;

    // The secret for decrypting this message.
    uint8_t sharedSecret[32];

    uint8_t* herPermKey = NULL;
    if (nonce < 2) {
        if (nonce == 0) {
            cryptoAuthDebug(wrapper, "Received a hello packet, using auth: %d",
                            (passwordHash != NULL));
        } else {
            cryptoAuthDebug0(wrapper, "Received a repeat hello packet");
        }

        // Decrypt message with perminent keys.
        if (!knowHerKey(wrapper) || wrapper->nextNonce == 0) {
            herPermKey = header->handshake.publicKey;
            #ifdef Log_DEBUG
                if (Bits_isZero(header->handshake.publicKey, 32)) {
                    cryptoAuthDebug0(wrapper, "Node sent public key of ZERO!");
                }
            #endif
        } else {
            herPermKey = wrapper->herPerminentPubKey;
            if (Bits_memcmp(header->handshake.publicKey, herPermKey, 32)) {
                cryptoAuthDebug0(wrapper, "DROP packet contains different perminent key");
                return Error_AUTHENTICATION;
            }
        }

        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        herPermKey,
                        passwordHash,
                        wrapper->context->logger);
        nextNonce = 2;
    } else {
        if (nonce == 2) {
            cryptoAuthDebug0(wrapper, "Received a key packet");
        } else if (nonce == 3) {
            cryptoAuthDebug0(wrapper, "Received a repeat key packet");
        } else {
            cryptoAuthDebug(wrapper, "Received a packet of unknown type! nonce=%u", nonce);
        }
        if (Bits_memcmp(header->handshake.publicKey, wrapper->herPerminentPubKey, 32)) {
            cryptoAuthDebug0(wrapper, "DROP packet contains different perminent key");
            return Error_AUTHENTICATION;
        }
        if (!wrapper->isInitiator) {
            cryptoAuthDebug0(wrapper, "DROP a stray key packet");
            return Error_AUTHENTICATION;
        }
        // We sent the hello, this is a key
        getSharedSecret(sharedSecret,
                        wrapper->ourTempPrivKey,
                        wrapper->herPerminentPubKey,
                        passwordHash,
                        wrapper->context->logger);
        nextNonce = 4;
    }

    // Shift it on top of the authenticator before the encrypted public key
    Message_shift(message, 48 - Headers_CryptoAuth_SIZE, NULL);

    #ifdef Log_KEYS
        uint8_t sharedSecretHex[65];
        printHexKey(sharedSecretHex, sharedSecret);
        uint8_t nonceHex[49];
        Hex_encode(nonceHex, 49, header->handshake.nonce, 24);
        uint8_t cipherHex[65];
        printHexKey(cipherHex, message->bytes);
        Log_keys(wrapper->context->logger,
                  "Decrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    #endif

    // Decrypt her temp public key and the message.
    if (decryptRndNonce(header->handshake.nonce, message, sharedSecret) != 0) {
        // just in case
        Bits_memset(header, 0, Headers_CryptoAuth_SIZE);
        cryptoAuthDebug(wrapper, "DROP message with nonce [%d], decryption failed", nonce);
        return Error_AUTHENTICATION;
    }

    Assert_ifParanoid(!Bits_isZero(header->handshake.encryptedTempKey, 32));

    #ifdef Log_KEYS
        uint8_t tempKeyHex[65];
        Hex_encode(tempKeyHex, 65, header->handshake.encryptedTempKey, 32);
        Log_keys(wrapper->context->logger,
                  "Unwrapping temp public key:\n"
                  "    %s\n",
                  tempKeyHex);
    #endif

    Message_shift(message, -32, NULL);

    // Post-decryption checking
    if (nonce == 0) {
        // A new hello packet
        if (!Bits_memcmp(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            // possible replay attack or duped packet
            cryptoAuthDebug0(wrapper, "DROP dupe hello packet with same temp key");
            return Error_AUTHENTICATION;
        }
    } else if (nonce == 2 && wrapper->nextNonce >= 4) {
        // we accept a new key packet and let it change the session since the other end might have
        // killed off the session while it was in the midst of setting up.
        if (!Bits_memcmp(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            Assert_true(!Bits_isZero(wrapper->herTempPubKey, 32));
            cryptoAuthDebug0(wrapper, "DROP dupe key packet with same temp key");
            return Error_AUTHENTICATION;
        }

    } else if (nonce == 3 && wrapper->nextNonce >= 4) {
        // Got a repeat key packet, make sure the temp key is the same as the one we know.
        if (Bits_memcmp(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            Assert_true(!Bits_isZero(wrapper->herTempPubKey, 32));
            cryptoAuthDebug0(wrapper, "DROP repeat key packet with different temp key");
            return Error_AUTHENTICATION;
        }
    }

    // If Alice sent a hello packet then Bob sent a hello packet and they crossed on the wire,
    // somebody has to yield and the other has to stand firm otherwise they will either deadlock
    // each believing their hello packet is superior or they will livelock, each switching to the
    // other's session and never synchronizing.
    // In this event whoever has the lower permanent public key wins.

    // If we receive a (possibly repeat) key packet
    if (nextNonce == 4) {
        if (wrapper->nextNonce <= 4) {
            // and have not yet begun sending "run" data
            Assert_true(wrapper->nextNonce <= nextNonce);
            wrapper->nextNonce = nextNonce;

            wrapper->user = user;
            Bits_memcpyConst(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32);
        } else {
            // It's a (possibly repeat) key packet and we have begun sending run data.
            // We will change the shared secret to the one specified in the new key packet but
            // intentionally avoid de-incrementing the nonce just in case
            getSharedSecret(wrapper->sharedSecret,
                            wrapper->ourTempPrivKey,
                            header->handshake.encryptedTempKey,
                            NULL,
                            wrapper->context->logger);
            cryptoAuthDebug0(wrapper, "New key packet but we are already sending data");
        }

    } else if (nextNonce == 2 && (!wrapper->isInitiator || wrapper->established)) {
        // This is a hello packet and we are either in ESTABLISHED state or we are
        // not the initiator of the connection.
        // If the case is that we are in ESTABLISHED state, the other side tore down the session
        // and we have not so lets tear it down.
        // If we are not in ESTABLISHED state then we don't allow resetting of the session unless
        // they are the sender of the hello packet or their permanent public key is lower.
        // this is a tie-breaker in case hello packets cross on the wire.
        if (wrapper->established) {
            reset(wrapper);
        }
        // We got a (possibly repeat) hello packet and we have not sent any hello packet,
        // new session.
        if (wrapper->nextNonce == 3 && nextNonce == 2) {
            // We sent a key packet so the next packet is a repeat key but we got another hello
            // We'll just keep steaming along sending repeat key packets
            nextNonce = 3;
        }

        Assert_true(wrapper->nextNonce <= nextNonce);
        wrapper->nextNonce = nextNonce;
        wrapper->user = user;
        Bits_memcpyConst(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32);

    } else if (nextNonce == 2
        && Bits_memcmp(header->handshake.publicKey, wrapper->context->pub.publicKey, 32) < 0)
    {
        // It's a hello and we are the initiator but their permant public key is numerically lower
        // than ours, this is so that in the event of two hello packets crossing on the wire, the
        // nodes will agree on who is the initiator.
        cryptoAuthDebug0(wrapper, "Incoming hello from node with lower key, resetting");
        reset(wrapper);

        Assert_true(wrapper->nextNonce <= nextNonce);
        wrapper->nextNonce = nextNonce;
        wrapper->user = user;
        Bits_memcpyConst(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32);

    } else {
        cryptoAuthDebug0(wrapper, "Incoming hello from node with higher key, not resetting");
    }

    if (herPermKey && herPermKey != wrapper->herPerminentPubKey) {
        Bits_memcpyConst(wrapper->herPerminentPubKey, herPermKey, 32);
    }

    // If this is a handshake which was initiated in reverse because we
    // didn't know the other node's key, now send what we were going to send.

    if (wrapper->bufferedMessage) {
        // This can only happen when we have received a (maybe repeat) hello packet.
        Assert_true(wrapper->nextNonce == 2);

        struct Message* bm = wrapper->bufferedMessage;
        wrapper->bufferedMessage = NULL;
        cryptoAuthDebug0(wrapper, "Sending buffered message");
        sendMessage(bm, &wrapper->externalInterface);
        Allocator_free(bm->alloc);
    }

    if (message->length == 0 && Headers_isSetupPacket(&header->handshake.auth)) {
        return Error_NONE;
    }

    Bits_memset(&wrapper->replayProtector, 0, sizeof(struct ReplayProtector));

    setRequiredPadding(wrapper);
    return callReceivedMessage(wrapper, message);
}
Example #9
0
static uint8_t encryptHandshake(struct Message* message,
                                struct CryptoAuth_Wrapper* wrapper,
                                int setupMessage)
{
    Message_shift(message, sizeof(union Headers_CryptoAuth), NULL);

    union Headers_CryptoAuth* header = (union Headers_CryptoAuth*) message->bytes;

    // garbage the auth challenge and set the nonce which follows it
    Random_bytes(wrapper->context->rand, (uint8_t*) &header->handshake.auth,
                 sizeof(union Headers_AuthChallenge) + 24);

    // set the permanent key
    Bits_memcpyConst(&header->handshake.publicKey, wrapper->context->pub.publicKey, 32);

    if (!knowHerKey(wrapper)) {
        return genReverseHandshake(message, wrapper, header);
    } else if (!Bits_isZero(wrapper->herIp6, 16)) {
        // If someone starts a CA session and then discovers the key later and memcpy's it into the
        // result of getHerPublicKey() then we want to make sure they didn't memcpy in an invalid
        // key.
        uint8_t calculatedIp6[16];
        AddressCalc_addressForPublicKey(calculatedIp6, wrapper->herPerminentPubKey);
        Assert_true(!Bits_memcmp(wrapper->herIp6, calculatedIp6, 16));
    }

    if (wrapper->bufferedMessage) {
        // We wanted to send a message but we didn't know the peer's key so we buffered it
        // and sent a connectToMe.
        // Now we just discovered their key and we're sending a hello packet.
        // Lets send 2 hello packets instead and on one will attach our buffered message.

        // This can never happen when the machine is beyond the first hello packet because
        // it should have been sent either by this or in the recipet of a hello packet from
        // the other node.
        Assert_true(wrapper->nextNonce == 0);

        struct Message* bm = wrapper->bufferedMessage;
        wrapper->bufferedMessage = NULL;
        cryptoAuthDebug0(wrapper, "Sending buffered message");
        sendMessage(bm, &wrapper->externalInterface);
        Allocator_free(bm->alloc);
    }

    // Password auth
    uint8_t* passwordHash = NULL;
    struct CryptoAuth_Auth auth;
    if (wrapper->password != NULL) {
        passwordHash = hashPassword(&auth, wrapper->password, wrapper->authType);
        Bits_memcpyConst(header->handshake.auth.bytes,
                         &auth.challenge,
                         sizeof(union Headers_AuthChallenge));
    }
    header->handshake.auth.challenge.type = wrapper->authType;

    // Packet authentication option is deprecated, it must always be enabled.
    Headers_setPacketAuthRequired(&header->handshake.auth, 1);

    // This is a special packet which the user should never see.
    Headers_setSetupPacket(&header->handshake.auth, setupMessage);

    // Set the session state
    uint32_t sessionState_be = Endian_hostToBigEndian32(wrapper->nextNonce);
    header->nonce = sessionState_be;

    if (wrapper->nextNonce == 0 || wrapper->nextNonce == 2) {
        // If we're sending a hello or a key
        // Here we make up a temp keypair
        Random_bytes(wrapper->context->rand, wrapper->ourTempPrivKey, 32);
        crypto_scalarmult_curve25519_base(wrapper->ourTempPubKey, wrapper->ourTempPrivKey);

        #ifdef Log_KEYS
            uint8_t tempPrivateKeyHex[65];
            Hex_encode(tempPrivateKeyHex, 65, wrapper->ourTempPrivKey, 32);
            uint8_t tempPubKeyHex[65];
            Hex_encode(tempPubKeyHex, 65, header->handshake.encryptedTempKey, 32);
            Log_keys(wrapper->context->logger, "Generating temporary keypair\n"
                                                "    myTempPrivateKey=%s\n"
                                                "     myTempPublicKey=%s\n",
                      tempPrivateKeyHex, tempPubKeyHex);
        #endif
    }

    Bits_memcpyConst(header->handshake.encryptedTempKey, wrapper->ourTempPubKey, 32);

    #ifdef Log_KEYS
        uint8_t tempKeyHex[65];
        Hex_encode(tempKeyHex, 65, header->handshake.encryptedTempKey, 32);
        Log_keys(wrapper->context->logger,
                  "Wrapping temp public key:\n"
                  "    %s\n",
                  tempKeyHex);
    #endif

    cryptoAuthDebug(wrapper, "Sending %s%s packet",
                    ((wrapper->nextNonce & 1) ? "repeat " : ""),
                    ((wrapper->nextNonce < 2) ? "hello" : "key"));

    uint8_t sharedSecret[32];
    if (wrapper->nextNonce < 2) {
        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        wrapper->herPerminentPubKey,
                        passwordHash,
                        wrapper->context->logger);

        wrapper->isInitiator = true;

        Assert_true(wrapper->nextNonce <= 1);
        wrapper->nextNonce = 1;
    } else {
        // Handshake2
        // herTempPubKey was set by receiveMessage()
        Assert_ifParanoid(!Bits_isZero(wrapper->herTempPubKey, 32));
        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        wrapper->herTempPubKey,
                        passwordHash,
                        wrapper->context->logger);

        Assert_true(wrapper->nextNonce <= 3);
        wrapper->nextNonce = 3;

        #ifdef Log_KEYS
            uint8_t tempKeyHex[65];
            Hex_encode(tempKeyHex, 65, wrapper->herTempPubKey, 32);
            Log_keys(wrapper->context->logger,
                      "Using their temp public key:\n"
                      "    %s\n",
                      tempKeyHex);
        #endif
    }

    // Shift message over the encryptedTempKey field.
    Message_shift(message, 32 - Headers_CryptoAuth_SIZE, NULL);

    encryptRndNonce(header->handshake.nonce, message, sharedSecret);

    #ifdef Log_KEYS
        uint8_t sharedSecretHex[65];
        printHexKey(sharedSecretHex, sharedSecret);
        uint8_t nonceHex[49];
        Hex_encode(nonceHex, 49, header->handshake.nonce, 24);
        uint8_t cipherHex[65];
        printHexKey(cipherHex, message->bytes);
        Log_keys(wrapper->context->logger,
                  "Encrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    #endif

    // Shift it back -- encryptRndNonce adds 16 bytes of authenticator.
    Message_shift(message, Headers_CryptoAuth_SIZE - 32 - 16, NULL);

    return wrapper->wrappedInterface->sendMessage(message, wrapper->wrappedInterface);
}
Example #10
0
static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
                                        const uint32_t nonce,
                                        struct Message* message,
                                        union CryptoHeader* header)
{
    if (message->length < CryptoHeader_SIZE) {
        cryptoAuthDebug0(session, "DROP runt");
        return -1;
    }

    // handshake
    // nextNonce 0: recieving hello.
    // nextNonce 1: recieving key, we sent hello.
    // nextNonce 2: recieving first data packet or duplicate hello.
    // nextNonce 3: recieving first data packet.
    // nextNonce >3: handshake complete

    if (knowHerKey(session)) {
        if (Bits_memcmp(session->pub.herPublicKey, header->handshake.publicKey, 32)) {
            cryptoAuthDebug0(session, "DROP a packet with different public key than this session");
            return -1;
        }
    } else if (Bits_isZero(session->pub.herIp6, 16)) {
        // ok fallthrough
    } else if (!ip6MatchesKey(session->pub.herIp6, header->handshake.publicKey)) {
        cryptoAuthDebug0(session, "DROP packet with public key not matching ip6 for session");
        return -1;
    }

    struct CryptoAuth_User* userObj = getAuth(&header->handshake.auth, session->context);
    uint8_t* restrictedToip6 = NULL;
    uint8_t* passwordHash = NULL;
    if (userObj) {
        passwordHash = userObj->secret;
        if (userObj->restrictedToip6[0]) {
            restrictedToip6 = userObj->restrictedToip6;
            if (!ip6MatchesKey(restrictedToip6, header->handshake.publicKey)) {
                cryptoAuthDebug0(session, "DROP packet with key not matching restrictedToip6");
                return -1;
            }
        }
    }
    if (session->requireAuth && !userObj) {
        cryptoAuthDebug0(session, "DROP message because auth was not given");
        return -1;
    }
    if (!userObj && header->handshake.auth.challenge.type != 0) {
        cryptoAuthDebug0(session, "DROP message with unrecognized authenticator");
        return -1;
    }
    // What the nextNonce will become if this packet is valid.
    uint32_t nextNonce;

    // The secret for decrypting this message.
    uint8_t sharedSecret[32];

    uint8_t* herPermKey = session->pub.herPublicKey;
    if (nonce < 2) {
        if (nonce == 0) {
            cryptoAuthDebug(session, "Received a hello packet, using auth: %d",
                            (userObj != NULL));
        } else {
            cryptoAuthDebug0(session, "Received a repeat hello packet");
        }

        // Decrypt message with perminent keys.
        if (!knowHerKey(session) || session->nextNonce == 0) {
            herPermKey = header->handshake.publicKey;
            if (Defined(Log_DEBUG) && Bits_isZero(header->handshake.publicKey, 32)) {
                cryptoAuthDebug0(session, "DROP Node sent public key of ZERO!");
                // This is strictly informational, we will not alter the execution path for it.
            }
        }

        getSharedSecret(sharedSecret,
                        session->context->privateKey,
                        herPermKey,
                        passwordHash,
                        session->context->logger);
        nextNonce = 2;
    } else {
        if (nonce == 2) {
            cryptoAuthDebug0(session, "Received a key packet");
        } else {
            Assert_true(nonce == 3);
            cryptoAuthDebug0(session, "Received a repeat key packet");
        }
        if (Bits_memcmp(header->handshake.publicKey, session->pub.herPublicKey, 32)) {
            cryptoAuthDebug0(session, "DROP packet contains different perminent key");
            return -1;
        }
        if (!session->isInitiator) {
            cryptoAuthDebug0(session, "DROP a stray key packet");
            return -1;
        }
        // We sent the hello, this is a key
        getSharedSecret(sharedSecret,
                        session->ourTempPrivKey,
                        session->pub.herPublicKey,
                        passwordHash,
                        session->context->logger);
        nextNonce = 4;
    }

    // Shift it on top of the authenticator before the encrypted public key
    Message_shift(message, 48 - CryptoHeader_SIZE, NULL);

    if (Defined(Log_KEYS)) {
        uint8_t sharedSecretHex[65];
        printHexKey(sharedSecretHex, sharedSecret);
        uint8_t nonceHex[49];
        Hex_encode(nonceHex, 49, header->handshake.nonce, 24);
        uint8_t cipherHex[65];
        printHexKey(cipherHex, message->bytes);
        Log_keys(session->context->logger,
                  "Decrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    }

    // Decrypt her temp public key and the message.
    if (decryptRndNonce(header->handshake.nonce, message, sharedSecret)) {
        // just in case
        Bits_memset(header, 0, CryptoHeader_SIZE);
        cryptoAuthDebug(session, "DROP message with nonce [%d], decryption failed", nonce);
        return -1;
    }

    if (Bits_isZero(header->handshake.encryptedTempKey, 32)) {
        // we need to reject 0 public keys outright because they will be confused with "unknown"
        cryptoAuthDebug0(session, "DROP message with zero as temp public key");
        return -1;
    }

    if (Defined(Log_KEYS)) {
        uint8_t tempKeyHex[65];
        Hex_encode(tempKeyHex, 65, header->handshake.encryptedTempKey, 32);
        Log_keys(session->context->logger,
                  "Unwrapping temp public key:\n"
                  "    %s\n",
                  tempKeyHex);
    }

    Message_shift(message, -32, NULL);

    // Post-decryption checking
    if (nonce == 0) {
        // A new hello packet
        if (!Bits_memcmp(session->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            // possible replay attack or duped packet
            cryptoAuthDebug0(session, "DROP dupe hello packet with same temp key");
            return -1;
        }
    } else if (nonce == 2 && session->nextNonce >= 4) {
        // we accept a new key packet and let it change the session since the other end might have
        // killed off the session while it was in the midst of setting up.
        // This is NOT a repeat key packet because it's nonce is 2, not 3
        if (!Bits_memcmp(session->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            Assert_true(!Bits_isZero(session->herTempPubKey, 32));
            cryptoAuthDebug0(session, "DROP dupe key packet with same temp key");
            return -1;
        }

    } else if (nonce == 3 && session->nextNonce >= 4) {
        // Got a repeat key packet, make sure the temp key is the same as the one we know.
        if (Bits_memcmp(session->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            Assert_true(!Bits_isZero(session->herTempPubKey, 32));
            cryptoAuthDebug0(session, "DROP repeat key packet with different temp key");
            return -1;
        }
    }

    // If Alice sent a hello packet then Bob sent a hello packet and they crossed on the wire,
    // somebody has to yield and the other has to stand firm otherwise they will either deadlock
    // each believing their hello packet is superior or they will livelock, each switching to the
    // other's session and never synchronizing.
    // In this event whoever has the lower permanent public key wins.

    // If we receive a (possibly repeat) key packet
    if (nextNonce == 4) {
        if (session->nextNonce <= 4) {
            // and have not yet begun sending "run" data
            Bits_memcpyConst(session->herTempPubKey, header->handshake.encryptedTempKey, 32);
        } else {
            // It's a (possibly repeat) key packet and we have begun sending run data.
            // We will change the shared secret to the one specified in the new key packet but
            // intentionally avoid de-incrementing the nonce just in case
            getSharedSecret(session->sharedSecret,
                            session->ourTempPrivKey,
                            header->handshake.encryptedTempKey,
                            NULL,
                            session->context->logger);
            nextNonce = session->nextNonce + 1;
            cryptoAuthDebug0(session, "New key packet but we are already sending data");
        }

    } else if (nextNonce != 2) {

        Assert_true(!"should never happen");

    } else if (!session->isInitiator || session->established) {
        // This is a hello packet and we are either in ESTABLISHED state or we are
        // not the initiator of the connection.
        // If the case is that we are in ESTABLISHED state, the other side tore down the session
        // and we have not so lets tear it down.
        // If we are not in ESTABLISHED state then we don't allow resetting of the session unless
        // they are the sender of the hello packet or their permanent public key is lower.
        // this is a tie-breaker in case hello packets cross on the wire.
        if (session->established) {
            cryptoAuthDebug0(session, "new hello during established session, resetting");
            reset(session);
        }
        // We got a (possibly repeat) hello packet and we have not sent any hello packet,
        // new session.
        if (session->nextNonce == 3) {
            // We sent a key packet so the next packet is a repeat key but we got another hello
            // We'll just keep steaming along sending repeat key packets
            nextNonce = 3;
        }

        Bits_memcpyConst(session->herTempPubKey, header->handshake.encryptedTempKey, 32);

    } else if (Bits_memcmp(header->handshake.publicKey, session->context->pub.publicKey, 32) < 0) {
        // It's a hello and we are the initiator but their permant public key is numerically lower
        // than ours, this is so that in the event of two hello packets crossing on the wire, the
        // nodes will agree on who is the initiator.
        cryptoAuthDebug0(session, "Incoming hello from node with lower key, resetting");
        reset(session);

        Bits_memcpyConst(session->herTempPubKey, header->handshake.encryptedTempKey, 32);

    } else {
        cryptoAuthDebug0(session, "DROP Incoming hello from node with higher key, not resetting");
        return -1;
    }

    if (herPermKey && herPermKey != session->pub.herPublicKey) {
        Bits_memcpyConst(session->pub.herPublicKey, herPermKey, 32);
    }
    if (restrictedToip6) {
        Bits_memcpyConst(session->pub.herIp6, restrictedToip6, 16);
    }

    // Nonces can never go backward and can only "not advance" if they're 0,1,2,3,4 session state.
    Assert_true(session->nextNonce < nextNonce ||
        (session->nextNonce <= 4 && nextNonce == session->nextNonce)
    );
    session->nextNonce = nextNonce;

    Bits_memset(&session->pub.replayProtector, 0, sizeof(struct ReplayProtector));

    return 0;
}
Example #11
0
static void encryptHandshake(struct Message* message,
                             struct CryptoAuth_Session_pvt* session,
                             int setupMessage)
{
    Message_shift(message, sizeof(union CryptoHeader), NULL);

    union CryptoHeader* header = (union CryptoHeader*) message->bytes;

    // garbage the auth challenge and set the nonce which follows it
    Random_bytes(session->context->rand, (uint8_t*) &header->handshake.auth,
                 sizeof(union CryptoHeader_Challenge) + 24);

    // set the permanent key
    Bits_memcpyConst(&header->handshake.publicKey, session->context->pub.publicKey, 32);

    Assert_true(knowHerKey(session));

    uint8_t calculatedIp6[16];
    AddressCalc_addressForPublicKey(calculatedIp6, session->pub.herPublicKey);
    if (!Bits_isZero(session->pub.herIp6, 16)) {
        // If someone starts a CA session and then discovers the key later and memcpy's it into the
        // result of getHerPublicKey() then we want to make sure they didn't memcpy in an invalid
        // key.
        Assert_true(!Bits_memcmp(session->pub.herIp6, calculatedIp6, 16));
    }

    // Password auth
    uint8_t* passwordHash = NULL;
    uint8_t passwordHashStore[32];
    if (session->password != NULL) {
        hashPassword(passwordHashStore,
                     &header->handshake.auth,
                     session->login,
                     session->password,
                     session->authType);
        passwordHash = passwordHashStore;
    } else {
        header->handshake.auth.challenge.type = session->authType;
        header->handshake.auth.challenge.additional = 0;
    }

    // Set the session state
    header->nonce = Endian_hostToBigEndian32(session->nextNonce);

    if (session->nextNonce == 0 || session->nextNonce == 2) {
        // If we're sending a hello or a key
        // Here we make up a temp keypair
        Random_bytes(session->context->rand, session->ourTempPrivKey, 32);
        crypto_scalarmult_curve25519_base(session->ourTempPubKey, session->ourTempPrivKey);

        if (Defined(Log_KEYS)) {
            uint8_t tempPrivateKeyHex[65];
            Hex_encode(tempPrivateKeyHex, 65, session->ourTempPrivKey, 32);
            uint8_t tempPubKeyHex[65];
            Hex_encode(tempPubKeyHex, 65, session->ourTempPubKey, 32);
            Log_keys(session->context->logger, "Generating temporary keypair\n"
                                                "    myTempPrivateKey=%s\n"
                                                "     myTempPublicKey=%s\n",
                      tempPrivateKeyHex, tempPubKeyHex);
        }
    }

    Bits_memcpyConst(header->handshake.encryptedTempKey, session->ourTempPubKey, 32);

    if (Defined(Log_KEYS)) {
        uint8_t tempKeyHex[65];
        Hex_encode(tempKeyHex, 65, header->handshake.encryptedTempKey, 32);
        Log_keys(session->context->logger,
                  "Wrapping temp public key:\n"
                  "    %s\n",
                  tempKeyHex);
    }

    cryptoAuthDebug(session, "Sending %s%s packet",
                    ((session->nextNonce & 1) ? "repeat " : ""),
                    ((session->nextNonce < 2) ? "hello" : "key"));

    uint8_t sharedSecret[32];
    if (session->nextNonce < 2) {
        getSharedSecret(sharedSecret,
                        session->context->privateKey,
                        session->pub.herPublicKey,
                        passwordHash,
                        session->context->logger);

        session->isInitiator = true;

        Assert_true(session->nextNonce <= 1);
        session->nextNonce = 1;
    } else {
        // Handshake2
        // herTempPubKey was set by decryptHandshake()
        Assert_ifParanoid(!Bits_isZero(session->herTempPubKey, 32));
        getSharedSecret(sharedSecret,
                        session->context->privateKey,
                        session->herTempPubKey,
                        passwordHash,
                        session->context->logger);

        Assert_true(session->nextNonce <= 3);
        session->nextNonce = 3;

        if (Defined(Log_KEYS)) {
            uint8_t tempKeyHex[65];
            Hex_encode(tempKeyHex, 65, session->herTempPubKey, 32);
            Log_keys(session->context->logger,
                      "Using their temp public key:\n"
                      "    %s\n",
                      tempKeyHex);
        }
    }

    // Shift message over the encryptedTempKey field.
    Message_shift(message, 32 - CryptoHeader_SIZE, NULL);

    encryptRndNonce(header->handshake.nonce, message, sharedSecret);

    if (Defined(Log_KEYS)) {
        uint8_t sharedSecretHex[65];
        printHexKey(sharedSecretHex, sharedSecret);
        uint8_t nonceHex[49];
        Hex_encode(nonceHex, 49, header->handshake.nonce, 24);
        uint8_t cipherHex[65];
        printHexKey(cipherHex, message->bytes);
        Log_keys(session->context->logger,
                  "Encrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    }

    // Shift it back -- encryptRndNonce adds 16 bytes of authenticator.
    Message_shift(message, CryptoHeader_SIZE - 32 - 16, NULL);
}
Example #12
0
static uint8_t encryptHandshake(struct Message* message,
                                struct CryptoAuth_Wrapper* wrapper,
                                int setupMessage)
{
    Message_shift(message, sizeof(union Headers_CryptoAuth));

    union Headers_CryptoAuth* header = (union Headers_CryptoAuth*) message->bytes;

    // garbage the auth challenge and set the nonce which follows it
    Random_bytes(wrapper->context->rand, (uint8_t*) &header->handshake.auth,
                 sizeof(union Headers_AuthChallenge) + 24);

    // set the permanent key
    Bits_memcpyConst(&header->handshake.publicKey, wrapper->context->pub.publicKey, 32);

    if (!knowHerKey(wrapper)) {
        return genReverseHandshake(message, wrapper, header);
    }

    if (wrapper->bufferedMessage) {
        // We wanted to send a message but we didn't know the peer's key so we buffered it
        // and sent a connectToMe, this or it's reply was lost in the network.
        // Now we just discovered their key and we're sending a hello packet.
        // Lets send 2 hello packets instead and on one will attach our buffered message.

        // This can never happen when the machine is beyond the first hello packet because
        // it should have been sent either by this or in the recipet of a hello packet from
        // the other node.
        Assert_true(wrapper->nextNonce == 0);

        struct Message* bm = wrapper->bufferedMessage;
        wrapper->bufferedMessage = NULL;
        cryptoAuthDebug0(wrapper, "Sending buffered message");
        sendMessage(bm, &wrapper->externalInterface);
        Allocator_free(bm->alloc);
    }

    // Password auth
    uint8_t* passwordHash = NULL;
    struct CryptoAuth_Auth auth;
    if (wrapper->password != NULL) {
        passwordHash = hashPassword(&auth, wrapper->password, wrapper->authType);
        Bits_memcpyConst(header->handshake.auth.bytes,
                         &auth.challenge,
                         sizeof(union Headers_AuthChallenge));
    }
    header->handshake.auth.challenge.type = wrapper->authType;

    Headers_setPacketAuthRequired(&header->handshake.auth, wrapper->authenticatePackets);

    // This is a special packet which the user should never see.
    Headers_setSetupPacket(&header->handshake.auth, setupMessage);

    // Set the session state
    uint32_t sessionState_be = Endian_hostToBigEndian32(wrapper->nextNonce);
    header->nonce = sessionState_be;

    if (wrapper->nextNonce == 0 || wrapper->nextNonce == 2) {
        // If we're sending a hello or a key
        Random_bytes(wrapper->context->rand, wrapper->secret, 32);
        crypto_scalarmult_curve25519_base(header->handshake.encryptedTempKey,  wrapper->secret);

        #ifdef Log_KEYS
            uint8_t tempPrivateKeyHex[65];
            Hex_encode(tempPrivateKeyHex, 65, wrapper->secret, 32);
            uint8_t tempPubKeyHex[65];
            Hex_encode(tempPubKeyHex, 65, header->handshake.encryptedTempKey, 32);
            Log_keys(wrapper->context->logger, "Generating temporary keypair\n"
                                                "    myTempPrivateKey=%s\n"
                                                "     myTempPublicKey=%s\n",
                      tempPrivateKeyHex, tempPubKeyHex);
        #endif
        if (wrapper->nextNonce == 0) {
            Bits_memcpyConst(wrapper->tempKey, header->handshake.encryptedTempKey, 32);
        }
        #ifdef Log_DEBUG
            Assert_true(!Bits_isZero(header->handshake.encryptedTempKey, 32));
            Assert_true(!Bits_isZero(wrapper->secret, 32));
        #endif
    } else if (wrapper->nextNonce == 3) {
        // Dupe key
        // If nextNonce is 1 then we have our pubkey stored in wrapper->tempKey,
        // If nextNonce is 3 we need to recalculate it each time
        // because tempKey the final secret.
        crypto_scalarmult_curve25519_base(header->handshake.encryptedTempKey,
                                          wrapper->secret);
    } else {
        // Dupe hello
        // wrapper->nextNonce == 1
        // Our public key is cached in wrapper->tempKey so lets copy it out.
        Bits_memcpyConst(header->handshake.encryptedTempKey, wrapper->tempKey, 32);
    }
    #ifdef Log_KEYS
        uint8_t tempKeyHex[65];
        Hex_encode(tempKeyHex, 65, header->handshake.encryptedTempKey, 32);
        Log_keys(wrapper->context->logger,
                  "Wrapping temp public key:\n"
                  "    %s\n",
                  tempKeyHex);
    #endif

    cryptoAuthDebug(wrapper, "Sending %s%s packet",
                    ((wrapper->nextNonce & 1) ? "repeat " : ""),
                    ((wrapper->nextNonce < 2) ? "hello" : "key"));

    uint8_t sharedSecret[32];
    if (wrapper->nextNonce < 2) {
        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        wrapper->herPerminentPubKey,
                        passwordHash,
                        wrapper->context->logger);

        wrapper->isInitiator = true;
        wrapper->nextNonce = 1;
    } else {
        // Handshake2 wrapper->tempKey holds her public temp key.
        // it was put there by receiveMessage()
        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        wrapper->tempKey,
                        passwordHash,
                        wrapper->context->logger);
        wrapper->nextNonce = 3;

        #ifdef Log_KEYS
            uint8_t tempKeyHex[65];
            Hex_encode(tempKeyHex, 65, wrapper->tempKey, 32);
            Log_keys(wrapper->context->logger,
                      "Using their temp public key:\n"
                      "    %s\n",
                      tempKeyHex);
        #endif
    }

    // Shift message over the encryptedTempKey field.
    Message_shift(message, 32 - Headers_CryptoAuth_SIZE);

    encryptRndNonce(header->handshake.nonce, message, sharedSecret);

    #ifdef Log_KEYS
        uint8_t sharedSecretHex[65];
        printHexKey(sharedSecretHex, sharedSecret);
        uint8_t nonceHex[49];
        Hex_encode(nonceHex, 49, header->handshake.nonce, 24);
        uint8_t cipherHex[65];
        printHexKey(cipherHex, message->bytes);
        Log_keys(wrapper->context->logger,
                  "Encrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    #endif
    #ifdef Log_DEBUG
        Assert_true(!Bits_isZero(header->handshake.encryptedTempKey, 32));
    #endif

    // Shift it back -- encryptRndNonce adds 16 bytes of authenticator.
    Message_shift(message, Headers_CryptoAuth_SIZE - 32 - 16);

    return wrapper->wrappedInterface->sendMessage(message, wrapper->wrappedInterface);
}