static int calculateAuth(Dict* message, String* password, String* cookieStr, struct Allocator* alloc) { // Calculate the hash of the password. String* hashHex = String_newBinary(NULL, 64, alloc); uint8_t passAndCookie[64]; uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0; snprintf((char*) passAndCookie, 64, "%s%u", password->bytes, cookie); uint8_t hash[32]; crypto_hash_sha256(hash, passAndCookie, strlen((char*) passAndCookie)); Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32); Dict_putString(message, String_new("hash", alloc), hashHex, alloc); Dict_putString(message, String_new("cookie", alloc), cookieStr, alloc); // serialize the message with the password hash uint8_t buffer[AdminClient_MAX_MESSAGE_SIZE]; struct Writer* writer = ArrayWriter_new(buffer, AdminClient_MAX_MESSAGE_SIZE, alloc); if (StandardBencSerializer_get()->serializeDictionary(writer, message)) { return -1; } int length = writer->bytesWritten; // calculate the hash of the message with the password hash crypto_hash_sha256(hash, buffer, length); // swap the hash of the message with the password hash into the location // where the password hash was. Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32); return 0; }
static int calculateAuth(Dict* message, String* password, String* cookieStr, struct Allocator* alloc) { // Calculate the hash of the password. String* hashHex = String_newBinary(NULL, 64, alloc); uint8_t passAndCookie[64]; uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0; snprintf((char*) passAndCookie, 64, "%s%u", password->bytes, cookie); uint8_t hash[32]; crypto_hash_sha256(hash, passAndCookie, CString_strlen((char*) passAndCookie)); Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32); Dict_putString(message, String_new("hash", alloc), hashHex, alloc); Dict_putString(message, String_new("cookie", alloc), cookieStr, alloc); // serialize the message with the password hash struct Message* msg = Message_new(0, AdminClient_MAX_MESSAGE_SIZE, alloc); BencMessageWriter_write(message, msg, NULL); // calculate the hash of the message with the password hash crypto_hash_sha256(hash, msg->bytes, msg->length); // swap the hash of the message with the password hash into the location // where the password hash was. Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32); return 0; }
static inline bool authValid(Dict* message, uint8_t* buffer, uint32_t length, struct Admin* admin) { String* cookieStr = Dict_getString(message, String_CONST("cookie")); uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0; if (!cookie) { int64_t* cookieInt = Dict_getInt(message, String_CONST("cookie")); cookie = (cookieInt) ? *cookieInt : 0; } uint64_t nowSecs = Time_currentTimeSeconds(admin->eventBase); String* submittedHash = Dict_getString(message, String_CONST("hash")); if (cookie > nowSecs || cookie < nowSecs - 20 || !submittedHash || submittedHash->len != 64) { return false; } uint8_t* hashPtr = (uint8_t*) strstr((char*) buffer, submittedHash->bytes); if (!hashPtr || !admin->password) { return false; } uint8_t passAndCookie[64]; snprintf((char*) passAndCookie, 64, "%s%u", admin->password->bytes, cookie); uint8_t hash[32]; crypto_hash_sha256(hash, passAndCookie, strlen((char*) passAndCookie)); Hex_encode(hashPtr, 64, hash, 32); crypto_hash_sha256(hash, buffer, length); Hex_encode(hashPtr, 64, hash, 32); return memcmp(hashPtr, submittedHash->bytes, 64) == 0; }
static Dict* makeLogMessage(struct Subscription* subscription, struct AdminLog* logger, enum Log_Level logLevel, const char* fullFilePath, uint32_t line, const char* format, va_list vaArgs, struct Allocator* alloc) { time_t now; time(&now); Dict* out = Dict_new(alloc); char* buff = Allocator_malloc(alloc, 20); Hex_encode((uint8_t*)buff, 20, subscription->streamId, 8); Dict_putString(out, String_new("streamId", alloc), String_new(buff, alloc), alloc); Dict_putInt(out, String_new("time", alloc), now, alloc); Dict_putString(out, String_new("level", alloc), String_new(Log_nameForLevel(logLevel), alloc), alloc); const char* shortName = getShortName(fullFilePath); Dict_putString(out, String_new("file", alloc), String_new((char*)shortName, alloc), alloc); Dict_putInt(out, String_new("line", alloc), line, alloc); String* message = String_vprintf(alloc, format, vaArgs); // Strip all of the annoying \n marks in the log entries. if (message->len > 0 && message->bytes[message->len - 1] == '\n') { message->len--; } Dict_putString(out, String_new("message", alloc), message, alloc); return out; }
/** Takes the path in host byte order. */ void AddrTools_printPath(uint8_t out[20], uint64_t path) { uint64_t path_be = Endian_hostToBigEndian64(path); uint8_t bytes[16]; Hex_encode(bytes, 16, (uint8_t*) &path_be, 8); out[ 0] = bytes[ 0]; out[ 1] = bytes[ 1]; out[ 2] = bytes[ 2]; out[ 3] = bytes[ 3]; out[ 4] = '.'; out[ 5] = bytes[ 4]; out[ 6] = bytes[ 5]; out[ 7] = bytes[ 6]; out[ 8] = bytes[ 7]; out[ 9] = '.'; out[10] = bytes[ 8]; out[11] = bytes[ 9]; out[12] = bytes[10]; out[13] = bytes[11]; out[14] = '.'; out[15] = bytes[12]; out[16] = bytes[13]; out[17] = bytes[14]; out[18] = bytes[15]; out[19] = '\0'; }
static inline void printHexKey(uint8_t output[65], uint8_t key[32]) { if (key) { Hex_encode(output, 65, key, 32); } else { memcpy(output, "NULL", 5); } }
static void subscribe(Dict* args, void* vcontext, String* txid) { struct AdminLog* log = (struct AdminLog*) vcontext; String* levelName = Dict_getString(args, String_CONST("level")); enum Log_Level level = (levelName) ? Log_levelForName(levelName->bytes) : Log_Level_DEBUG; int64_t* lineNumPtr = Dict_getInt(args, String_CONST("line")); String* fileStr = Dict_getString(args, String_CONST("file")); const char* file = (fileStr && fileStr->len > 0) ? fileStr->bytes : NULL; char* error = "2+2=5"; if (level == Log_Level_INVALID) { level = Log_Level_KEYS; } if (lineNumPtr && *lineNumPtr < 0) { error = "Invalid line number, must be positive or 0 to signify any line is acceptable."; } else if (log->subscriptionCount >= MAX_SUBSCRIPTIONS) { error = "Max subscription count reached."; } else { struct Subscription* sub = &log->subscriptions[log->subscriptionCount]; sub->level = level; sub->alloc = Allocator_child(log->alloc); if (file) { int i; for (i = 0; i < FILE_NAME_COUNT; i++) { if (log->fileNames[i] && !strcmp(log->fileNames[i], file)) { file = log->fileNames[i]; sub->internalName = true; break; } } if (i == FILE_NAME_COUNT) { file = String_new(file, sub->alloc)->bytes; sub->internalName = false; } } sub->file = file; sub->lineNum = (lineNumPtr) ? *lineNumPtr : 0; sub->txid = String_clone(txid, sub->alloc); Random_bytes(log->rand, (uint8_t*) sub->streamId, 8); uint8_t streamIdHex[20]; Hex_encode(streamIdHex, 20, sub->streamId, 8); Dict response = Dict_CONST( String_CONST("error"), String_OBJ(String_CONST("none")), Dict_CONST( String_CONST("streamId"), String_OBJ(String_CONST((char*)streamIdHex)), NULL )); Admin_sendMessage(&response, txid, log->admin); log->subscriptionCount++; return; } Dict response = Dict_CONST( String_CONST("error"), String_OBJ(String_CONST(error)), NULL ); Admin_sendMessage(&response, txid, log->admin); }
static Iface_DEFUN incomingTunA(struct Message* msg, struct Iface* tunA) { struct TwoNodes* tn = Identity_containerOf(tunA, struct TwoNodes, tunA); Assert_true(TUNMessageType_pop(msg, NULL) == Ethernet_TYPE_IP6); Message_shift(msg, -Headers_IP6Header_SIZE, NULL); uint8_t buff[1024]; Hex_encode(buff, 1024, msg->bytes, msg->length); printf("Message from TUN in node A [%s] [%d] [%s]\n", msg->bytes, msg->length, buff); tn->messageFrom = TUNA; return 0; }
int main() { /* verify public key */ struct Address address; crypto_scalarmult_curve25519_base(address.key, privateKey); AddressCalc_addressForPublicKey(address.ip6.bytes, address.key); uint8_t privateKeyHexOut[65]; uint8_t publicKeyHexOut[65]; uint8_t publicKeyBase32Out[53]; Hex_encode(privateKeyHexOut, 65, privateKey, 32); Hex_encode(publicKeyHexOut, 65, publicKey, 32); printf("Private key %s (hex)\n\nExpect:\nPublic Key: %s (hex)\n" "Public Key: %s (base32)\nAddress: %s\n", privateKeyHexOut, publicKeyHexOut, publicKeyBase32, ipv6); uint8_t addressOut[40]; Hex_encode(publicKeyHexOut, 65, address.key, 32); Base32_encode(publicKeyBase32Out, 53, address.key, 32); Address_printIp(addressOut, &address); printf("\nGot:\nPublic Key: %s (hex)\n" "Public Key: %s (base32)\nAddress: %s\n", publicKeyHexOut, publicKeyBase32Out, addressOut); Assert_always(0 == memcmp(address.key, publicKey, 32)); Assert_always(0 == strcmp(publicKeyBase32, (char*) publicKeyBase32Out)); Assert_always(0 == strcmp(ipv6, (char*) addressOut)); }
static void encryptRndNonceTest() { uint8_t buff[44]; Bits_memset(buff, 0, 44); uint8_t nonce[24]; Bits_memset(nonce, 0, 24); uint8_t secret[32]; Bits_memset(secret, 0, 32); struct Message m = { .bytes=&buff[32], .length=12, .padding=32}; CString_strcpy((char*) m.bytes, "hello world"); CryptoAuth_encryptRndNonce(nonce, &m, secret); uint8_t* expected = (uint8_t*) "1391ac5d03ba9f7099bffbb6e6c69d67ae5bd79391a5b94399b293dc"; uint8_t output[57]; Hex_encode(output, 57, m.bytes, m.length); //printf("\n%s\n%s\n", (char*) expected, (char*) output); Assert_true(!Bits_memcmp(expected, output, 56)); Assert_true(!CryptoAuth_decryptRndNonce(nonce, &m, secret)); Assert_true(m.length == 12 && !Bits_memcmp(m.bytes, "hello world", m.length)); } static struct Random* evilRandom(struct Allocator* alloc, struct Log* logger) { struct RandomSeed* evilSeed = DeterminentRandomSeed_new(alloc); return Random_newWithSeed(alloc, logger, evilSeed, NULL); } static void createNew() { struct Allocator* allocator = MallocAllocator_new(BUFFER_SIZE); struct CryptoAuth* ca = CryptoAuth_new(allocator, privateKey, eventBase, NULL, evilRandom(allocator, NULL)); /*for (int i = 0; i < 32; i++) { printf("%.2x", ca->publicKey[i]); }*/ Assert_true(Bits_memcmp(ca->publicKey, publicKey, 32) == 0); Allocator_free(allocator); } static uint8_t receiveMessage(struct Message* message, struct Interface* iface) { Message_pop(message, NULL, 4, NULL); *((struct Message**)iface->receiverContext) = message; return Error_NONE; }
void AddrTools_printShortIp(uint8_t output[40], const uint8_t binIp[16]) { /* The chances of hitting :0:0: and breaking * RFC5952 are 1 in (1 / (2^16))^2 * 6. * E. Siler */ char *p = output; int i = 0; for (; i < 16;) { if ((size_t)p != (size_t)output) { *p++= ':'; } if (binIp[i] > 0x0F) { Hex_encode(p, 2, &binIp[i++], 1); p += 2; } else if (binIp[i] > 0x00) { *p++ = Hex_encodeLowNibble(binIp[i++]); } else { ++i; if (binIp[i] > 0x0F) { Hex_encode(p, 2, &binIp[i++], 1); p += 2; } else { *p++ = Hex_encodeLowNibble(binIp[i++]); } continue; } Hex_encode(p, 2, &binIp[i++], 1); p += 2; } *p = '\0'; Assert_true((size_t)p <= ((size_t)output + 40)); Assert_true(i <= 16); }
void AddrTools_printIp(uint8_t output[40], const uint8_t binIp[16]) { uint8_t hex[32]; Hex_encode(hex, 32, binIp, 16); output[ 0] = hex[ 0]; output[ 1] = hex[ 1]; output[ 2] = hex[ 2]; output[ 3] = hex[ 3]; output[ 4] = ':'; output[ 5] = hex[ 4]; output[ 6] = hex[ 5]; output[ 7] = hex[ 6]; output[ 8] = hex[ 7]; output[ 9] = ':'; output[10] = hex[ 8]; output[11] = hex[ 9]; output[12] = hex[10]; output[13] = hex[11]; output[14] = ':'; output[15] = hex[12]; output[16] = hex[13]; output[17] = hex[14]; output[18] = hex[15]; output[19] = ':'; output[20] = hex[16]; output[21] = hex[17]; output[22] = hex[18]; output[23] = hex[19]; output[24] = ':'; output[25] = hex[20]; output[26] = hex[21]; output[27] = hex[22]; output[28] = hex[23]; output[29] = ':'; output[30] = hex[24]; output[31] = hex[25]; output[32] = hex[26]; output[33] = hex[27]; output[34] = ':'; output[35] = hex[28]; output[36] = hex[29]; output[37] = hex[30]; output[38] = hex[31]; output[39] = '\0'; }
static void pingResponse(struct RouterModule_Promise* promise, uint32_t lag, struct Node* node, Dict* responseDict) { struct Ping* ping = Identity_cast((struct Ping*)promise->userData); uint8_t versionStr[40] = "old"; String* version = String_CONST((char*)versionStr); String* versionBin = Dict_getString(responseDict, CJDHTConstants_VERSION); if (versionBin && versionBin->len == 20) { Hex_encode(versionStr, 40, (uint8_t*) versionBin->bytes, 20); version->len = 40; } int64_t* protocolVersion = Dict_getInt(responseDict, CJDHTConstants_PROTOCOL); int64_t pv = (protocolVersion) ? *protocolVersion : -1; Dict response = NULL; Dict verResponse = Dict_CONST(String_CONST("version"), String_OBJ(version), response); if (versionBin) { response = verResponse; } String* result = (responseDict) ? String_CONST("pong") : String_CONST("timeout"); response = Dict_CONST(String_CONST("result"), String_OBJ(result), response); Dict protoResponse = Dict_CONST(String_CONST("protocol"), Int_OBJ(pv), response); if (protocolVersion) { response = protoResponse; } response = Dict_CONST(String_CONST("ms"), Int_OBJ(lag), response); char from[60] = ""; if (node) { Address_print((uint8_t*)from, &node->address); } Dict fromResponse = Dict_CONST(String_CONST("from"), String_OBJ(String_CONST(from)), response); if (node) { response = fromResponse; } Admin_sendMessage(&response, ping->txid, ping->ctx->admin); }
List* EncodingScheme_asList(struct EncodingScheme* list, struct Allocator* alloc) { Assert_true(EncodingScheme_isSane(list)); String* prefixLen = String_new("prefixLen", alloc); String* bitCount = String_new("bitCount", alloc); String* prefix = String_new("prefix", alloc); List* scheme = NULL; for (int i = 0; i < (int)list->count; i++) { Dict* form = Dict_new(alloc); Dict_putInt(form, prefixLen, list->forms[i].prefixLen, alloc); Dict_putInt(form, bitCount, list->forms[i].bitCount, alloc); String* pfx = String_newBinary(NULL, 8, alloc); uint32_t prefix_be = Endian_hostToBigEndian32(list->forms[i].prefix); Hex_encode(pfx->bytes, 8, (uint8_t*)&prefix_be, 4); Dict_putString(form, prefix, pfx, alloc); scheme = List_addDict(scheme, form, alloc); } return scheme; }
static int genAddress(uint8_t addressOut[40], uint8_t privateKeyHexOut[65], uint8_t publicKeyBase32Out[53]) { struct Address address; uint8_t privateKey[32]; for (;;) { randombytes(privateKey, 32); crypto_scalarmult_curve25519_base(address.key, privateKey); AddressCalc_addressForPublicKey(address.ip6.bytes, address.key); // Brute force for keys until one matches FC00:/8 if (address.ip6.bytes[0] == 0xFC) { Hex_encode(privateKeyHexOut, 65, privateKey, 32); Base32_encode(publicKeyBase32Out, 53, address.key, 32); Address_printIp(addressOut, &address); return 0; } } }
int main(int argc, char** argv) { struct Allocator* alloc = MallocAllocator_new(1<<22); struct Random* rand = Random_new(alloc, NULL, NULL); uint8_t privateKey[32]; uint8_t publicKey[32]; uint8_t ip[16]; uint8_t hexPrivateKey[65]; uint8_t printedIp[40]; for (;;) { Random_bytes(rand, privateKey, 32); crypto_scalarmult_curve25519_base(publicKey, privateKey); if (AddressCalc_addressForPublicKey(ip, publicKey)) { Hex_encode(hexPrivateKey, 65, privateKey, 32); AddrTools_printIp(printedIp, ip); printf("%s %s\n", hexPrivateKey, printedIp); } } return 0; }
int main() { struct Allocator* alloc = MallocAllocator_new(20000); struct Random* rand = Random_new(alloc, NULL, NULL); uint8_t bytes[32]; Random_bytes(rand, bytes, 32); uint8_t hex[65] = {0}; Assert_true(Hex_encode(hex, 65, bytes, 32) == 64); //printf("hex encoded: %s\n", hex); uint8_t bytes2[32]; Assert_true(Hex_decode(bytes2, 32, hex, 64) == 32); Assert_true(Bits_memcmp(bytes, bytes2, 32) == 0); Allocator_free(alloc); return 0; }
static int genAddress(uint8_t addressOut[40], uint8_t privateKeyHexOut[65], uint8_t publicKeyBase32Out[53], uint8_t privateKey[32]) { struct Address address; crypto_scalarmult_curve25519_base(address.key, privateKey); AddressCalc_addressForPublicKey(address.ip6.bytes, address.key); // Brute force for keys until one matches FC00:/8 if( address.ip6.bytes[0] == 0xFC// && //(address.ip6.bytes[15] & 0xF) == (address.ip6.bytes[15] & 0x0F << 4) && //address.ip6.bytes[14] == address.ip6.bytes[15] ) { Hex_encode(privateKeyHexOut, 65, privateKey, 32); Base32_encode(publicKeyBase32Out, 53, address.key, 32); Address_printIp(addressOut, &address); return 1; } return 0; }
void encryptRndNonceTest() { uint8_t buff[44]; memset(buff, 0, 44); uint8_t nonce[24]; memset(nonce, 0, 24); uint8_t secret[32]; memset(secret, 0, 32); struct Message m = { .bytes=&buff[32], .length=12, .padding=32}; strcpy((char*) m.bytes, "hello world"); Exports_encryptRndNonce(nonce, &m, secret); uint8_t* expected = (uint8_t*) "1391ac5d03ba9f7099bffbb6e6c69d67ae5bd79391a5b94399b293dc"; uint8_t output[57]; Hex_encode(output, 57, m.bytes, m.length); //printf("\n%s\n%s\n", (char*) expected, (char*) output); Assert_always(!memcmp(expected, output, 56)); Assert_always(!Exports_decryptRndNonce(nonce, &m, secret)); Assert_always(m.length == 12 && !memcmp(m.bytes, "hello world", m.length)); } void createNew() { uint8_t buff[BUFFER_SIZE]; struct Allocator* allocator = BufferAllocator_new(buff, BUFFER_SIZE); struct CryptoAuth* ca = CryptoAuth_new(allocator, privateKey, eventBase, NULL); /*for (int i = 0; i < 32; i++) { printf("%.2x", ca->publicKey[i]); }*/ Assert_always(memcmp(ca->publicKey, publicKey, 32) == 0); }
void AddrTools_printMac(uint8_t output[18], const uint8_t binMac[6]) { uint8_t hex[12]; Hex_encode(hex, 12, binMac, 6); output[ 0] = hex[ 0]; output[ 1] = hex[ 1]; output[ 2] = ':'; output[ 3] = hex[ 2]; output[ 4] = hex[ 3]; output[ 5] = ':'; output[ 6] = hex[ 4]; output[ 7] = hex[ 5]; output[ 8] = ':'; output[ 9] = hex[ 6]; output[10] = hex[ 7]; output[11] = ':'; output[12] = hex[ 8]; output[13] = hex[ 9]; output[14] = ':'; output[15] = hex[10]; output[16] = hex[11]; output[17] = '\0'; }
static void pingResponse(struct RouterModule_Promise* promise, uint32_t lag, struct Address* from, Dict* responseDict) { struct Ping* ping = Identity_check((struct Ping*)promise->userData); struct Allocator* tempAlloc = promise->alloc; Dict* resp = Dict_new(tempAlloc); String* versionBin = Dict_getString(responseDict, CJDHTConstants_VERSION); if (versionBin && versionBin->len == 20) { String* versionStr = String_newBinary(NULL, 40, tempAlloc); Hex_encode(versionStr->bytes, 40, versionBin->bytes, 20); Dict_putString(resp, String_CONST("version"), versionStr, tempAlloc); } else { Dict_putString(resp, String_CONST("version"), String_CONST("unknown"), tempAlloc); } String* result = (responseDict) ? String_CONST("pong") : String_CONST("timeout"); Dict_putString(resp, String_CONST("result"), result, tempAlloc); int64_t* protocolVersion = Dict_getInt(responseDict, CJDHTConstants_PROTOCOL); if (protocolVersion) { Dict_putInt(resp, String_CONST("protocol"), *protocolVersion, tempAlloc); } Dict_putInt(resp, String_CONST("ms"), lag, tempAlloc); if (from) { uint8_t fromStr[60] = ""; Address_print(fromStr, from); Dict_putString(resp, String_CONST("from"), String_new(fromStr, tempAlloc), tempAlloc); } Admin_sendMessage(resp, ping->txid, ping->ctx->admin); }
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); }
static int reconnectionNewEndpointTest(struct InterfaceController* ifController, uint8_t* pk, struct Message** fromSwitchPtr, struct Allocator* alloc, struct EventBase* eventBase, struct Log* logger, struct Interface* routerIf, struct Random* rand) { struct Message* message; struct Interface iface = { .sendMessage = messageFromInterface, .senderContext = &message, .allocator = alloc }; uint8_t* buffer = Allocator_malloc(alloc, 512); struct Message* outgoing = &(struct Message) { .length = 0, .padding = 512, .bytes = buffer + 512 }; struct CryptoAuth* externalCa = CryptoAuth_new(alloc, NULL, eventBase, logger, rand); struct Interface* wrapped = CryptoAuth_wrapInterface(&iface, pk, NULL, false, "", externalCa); CryptoAuth_setAuth(String_CONST("passwd"), 1, wrapped); struct Interface icIface = { .allocator = alloc, .sendMessage = messageFromInterface, .senderContext = &message }; InterfaceController_registerPeer(ifController, NULL, NULL, true, false, &icIface); uint8_t hexBuffer[1025]; for (int i = 0; i < 4; i++) { outgoing->length = 0; outgoing->padding = 512; outgoing->bytes = buffer + 512; Message_shift(outgoing, 12, NULL); Bits_memcpyConst(outgoing->bytes, "hello world", 12); Message_shift(outgoing, SwitchHeader_SIZE, NULL); Bits_memcpyConst(outgoing->bytes, (&(struct SwitchHeader) { .label_be = Endian_hostToBigEndian64(1), .lowBits_be = 0 }), SwitchHeader_SIZE); wrapped->sendMessage(outgoing, wrapped); *fromSwitchPtr = NULL; icIface.receiveMessage(outgoing, &icIface); message = *fromSwitchPtr; Assert_true(message); Assert_true(message->length == 24); Hex_encode(hexBuffer, 1025, message->bytes, message->length); printf("%s\n", hexBuffer); // Need to bounce the packets back when connecting after the first try. // This is needed to establish the CryptoAuth session and make the InterfaceController // merge the endpoints. if (i > 0) { // Reverse the bits to reverse the path: uint64_t path; Bits_memcpyConst(&path, message->bytes, 8); path = Bits_bitReverse64(path); Bits_memcpyConst(message->bytes, &path, 8); printf("sending back response.\n"); routerIf->receiveMessage(message, routerIf); printf("forwarding response to external cryptoAuth.\n"); iface.receiveMessage(message, &iface); printf("forwarded.\n"); } else { printf("not responding because we don't want to establish a connection yet.\n"); } } // check everything except the label Assert_true(!CString_strcmp((char*)hexBuffer+16, "0000000068656c6c6f20776f726c6400")); // check label: make sure the interface has been switched back into position 0. uint64_t label_be; Hex_decode((uint8_t*) &label_be, 8, hexBuffer, 16); uint64_t rev_label = Bits_bitReverse64(Endian_bigEndianToHost64(label_be)); // check label is decoded to 0 Assert_true(0 == NumberCompress_getDecompressed(rev_label, NumberCompress_bitsUsedForLabel(rev_label))); // check no other bits are set uint64_t out = NumberCompress_getCompressed(0, NumberCompress_bitsUsedForLabel(rev_label)); Assert_true(rev_label == out); return 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); }
static int handleOutgoing(struct DHTMessage* dmessage, void* vcontext) { struct Ducttape* context = (struct Ducttape*) vcontext; struct Message message = { .length = dmessage->length, .bytes = (uint8_t*) dmessage->bytes, .padding = 512 }; Message_shift(&message, Headers_UDPHeader_SIZE); struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message.bytes; uh->sourceAndDestPorts = 0; uh->length_be = Endian_hostToBigEndian16(dmessage->length); uh->checksum_be = 0; uint16_t payloadLength = message.length; Message_shift(&message, Headers_IP6Header_SIZE); struct Headers_IP6Header* header = (struct Headers_IP6Header*) message.bytes; header->versionClassAndFlowLabel = 0; header->flowLabelLow_be = 0; header->nextHeader = 17; header->hopLimit = 0; header->payloadLength_be = Endian_hostToBigEndian16(payloadLength); Bits_memcpyConst(header->sourceAddr, context->myAddr.ip6.bytes, Address_SEARCH_TARGET_SIZE); Bits_memcpyConst(header->destinationAddr, dmessage->address->ip6.bytes, Address_SEARCH_TARGET_SIZE); context->ip6Header = header; context->switchHeader = NULL; sendToRouter(dmessage->address, &message, context); return 0; } // Aligned on the beginning of the content. static inline bool isRouterTraffic(struct Message* message, struct Headers_IP6Header* ip6) { if (ip6->nextHeader != 17 || ip6->hopLimit != 0) { return false; } struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes; return message->length >= Headers_UDPHeader_SIZE && uh->sourceAndDestPorts == 0 && (int) Endian_bigEndianToHost16(uh->length_be) == message->length - Headers_UDPHeader_SIZE; } /** * Message which is for us, message is aligned on the beginning of the content. * this is called from core() which calls through an interfaceMap. */ static inline uint8_t incomingForMe(struct Message* message, struct Ducttape* context, uint8_t herPubKey[32]) { struct Address addr; AddressCalc_addressForPublicKey(addr.ip6.bytes, herPubKey); if (memcmp(addr.ip6.bytes, context->ip6Header->sourceAddr, 16)) { #ifdef Log_DEBUG uint8_t keyAddr[40]; Address_printIp(keyAddr, &addr); Bits_memcpyConst(addr.ip6.bytes, context->ip6Header->sourceAddr, 16); uint8_t srcAddr[40]; Address_printIp(srcAddr, &addr); Log_debug2(context->logger, "Dropped packet because source address is not same as key.\n" " %s source addr\n" " %s hash of key\n", srcAddr, keyAddr); #endif return Error_INVALID; } if (message->length == 0) { #ifdef Log_WARN uint8_t keyAddr[40]; uint8_t ipv6Hex[80]; Address_printIp(keyAddr, &addr); Hex_encode(ipv6Hex, 80, (uint8_t*) context->ip6Header, 40); Log_warn2(context->logger, "Got ipv6 packet from %s which has no content!\nIPv6 Header: [%s]", keyAddr, ipv6Hex); #endif return Error_INVALID; } if (isRouterTraffic(message, context->ip6Header)) { // Shift off the UDP header. Message_shift(message, -Headers_UDPHeader_SIZE); addr.path = Endian_bigEndianToHost64(context->switchHeader->label_be); Bits_memcpyConst(addr.key, herPubKey, 32); return incomingDHT(message, &addr, context); } // RouterModule_addNode(&addr, context->routerModule); if (!context->routerIf) { Log_warn(context->logger, "Dropping message because there is no router interface configured.\n"); return Error_UNDELIVERABLE; } // Now write a message to the TUN device. // Need to move the ipv6 header forward up to the content because there's a crypto header // between the ipv6 header and the content which just got eaten. Message_shift(message, Headers_IP6Header_SIZE); uint16_t sizeDiff = message->bytes - (uint8_t*)context->ip6Header; if (sizeDiff) { context->ip6Header->payloadLength_be = Endian_hostToBigEndian16( Endian_bigEndianToHost16(context->ip6Header->payloadLength_be) - sizeDiff); memmove(message->bytes, context->ip6Header, Headers_IP6Header_SIZE); } context->routerIf->sendMessage(message, context->routerIf); return Error_NONE; } uint8_t Ducttape_injectIncomingForMe(struct Message* message, struct Ducttape* context, uint8_t herPublicKey[32]) { struct Headers_SwitchHeader sh; Bits_memcpyConst(&sh, message->bytes, Headers_SwitchHeader_SIZE); context->switchHeader = &sh; Message_shift(message, -Headers_SwitchHeader_SIZE); struct Headers_IP6Header ip6; Bits_memcpyConst(&ip6, message->bytes, Headers_IP6Header_SIZE); context->ip6Header = &ip6; Message_shift(message, -Headers_IP6Header_SIZE); return incomingForMe(message, context, herPublicKey); } /** * Send a message to another switch. * Switchheader will precede the message. */ static inline uint8_t sendToSwitch(struct Message* message, struct Headers_SwitchHeader* destinationSwitchHeader, struct Ducttape* context) { Message_shift(message, Headers_SwitchHeader_SIZE); struct Headers_SwitchHeader* switchHeaderLocation = (struct Headers_SwitchHeader*) message->bytes; if (destinationSwitchHeader != switchHeaderLocation) { memmove(message->bytes, destinationSwitchHeader, Headers_SwitchHeader_SIZE); } return context->switchInterface.receiveMessage(message, &context->switchInterface); }
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); }
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; }
static uint8_t receiveMessage(struct Message* msg, struct Iface* iface) { struct Allocator* alloc = iface->receiverContext; if (msg->length < 20) { printf("runt\n"); return 0; } // ethernet padding. Message_shift(msg, -2, NULL); uint8_t from[13]; uint8_t to[13]; Hex_encode(from, 13, msg->bytes, 6); Message_shift(msg, -6, NULL); Hex_encode(to, 13, msg->bytes, 6); Message_shift(msg, -6, NULL); uint8_t type[5]; Hex_encode(type, 5, msg->bytes, 2); Message_shift(msg, -2, NULL); int subsubtype = -1; int subtype = -1; // int typeCode = -1; if (!Bits_memcmp(type, "86dd", 4)) { Bits_memcpy(type, "ipv6", 5); subtype = msg->bytes[6]; // typeCode = 6; if (subtype == 58) { subsubtype = msg->bytes[40]; } } else if (!Bits_memcmp(type, "0800", 4)) { return 0; Bits_memcpy(type, "ipv4", 5); subtype = msg->bytes[9]; // typeCode = 4; } else { return 0; } // 6000000000183aff0000000000000000000000000000000fff0200000000000000000001ff000018 870 //6000000000201101fd000000000000000000000000000001ff020000000000000000000000010003 eee914... //6000000000083aff00000000000000000000000000000000ff020000000000000000000000000002 85007b //6000000000203aff fd000000000000000000000000000001 ff0200000000000000000001ff000002 8700. int len = msg->length * 2 + 1; uint8_t* buff = Allocator_malloc(alloc, len + 2); Hex_encode(buff, len, msg->bytes, msg->length); /* if (typeCode == 6 && len > 86) { Bits_memmove(&buff[82], &buff[81], len - 81); Bits_memmove(&buff[49], &buff[48], len - 48); Bits_memmove(&buff[17], &buff[16], len - 16); buff[80] = buff[48] = buff[16] = ' '; }*/ if (msg->length > 45) { Bits_memcpy(buff+86, "...", 4); } printf("[%s] [%s] [%s] [%02d] [%03d] [%s]\n", to, from, type, subtype, subsubtype, buff); return 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); }
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); }