char gen_bit(int index) { char* R = new char[BLOCK_SIZE]; copy_bytes(I, R); // R = I xor_bytes(S, R); // R = I xor S //cout << "R = I xor S = "; print_hex(R, BLOCK_SIZE); cout << endl; char* X = f(R); // X = f(R, k) //cout << "X = f(R, K) = "; print_hex(X, BLOCK_SIZE); cout << endl; char* T = new char[BLOCK_SIZE]; copy_bytes(X, T); xor_bytes(I, T); // T = X xor I //cout << "T = X xor I = "; print_hex(T, BLOCK_SIZE); cout << endl; S = f(T); // S = f(T, K) //cout << "S = f(T, K) = "; print_hex(S, BLOCK_SIZE); cout << endl; int i = index / 8; index %= 8; char mask = 1; mask <<= index; char bit = X[i] & mask; if (index == 7) { bit >>= 1; bit &= 0x7f; bit >>= index - 1; } else {
/* * plaintext, message length in byte, ciphertext, associated data, and associated data length in byte tag, and tag length in byte */ int ae_encrypt(ae_cxt* cxt, byte* pt, unsigned long long mlen, byte* ct, byte* tag, unsigned long long tlen, int enc_dec) { cxt->pt = pt; cxt->ptlen = mlen; cxt->ct = ct; cxt->ctlen = mlen; cxt->tag = tag; cxt->tlen = tlen; byte* es = cxt->es; byte* ts = cxt->ts; unsigned long long pc = 0; while((pc + STATE_LEN) < mlen){ if(enc_dec == ENC){ // encryption xor_bytes(es, pt+pc, STATE_LEN); memcpy(ct+pc, es, STATE_LEN); } else{ // decryption xor_bytes2(pt+pc, ct+pc, es, STATE_LEN); memcpy(es, ct+pc, STATE_LEN); } xor_bytes(ts, es, STATE_LEN); present_enc(ts, cxt->userkey); /* apply fix1 */ es[0] |= 0x80; present_enc(es, cxt->userkey); pc += STATE_LEN; } /* process the last block */ unsigned long long lastblocklen = mlen - pc; if(lastblocklen > 0){ if(enc_dec == ENC){ // encryption xor_bytes(es, pt+pc, lastblocklen); memcpy(ct+pc, es, lastblocklen); } else{ // decryption xor_bytes2(pt+pc, ct+pc, es, lastblocklen); memcpy(es, ct+pc, lastblocklen); } xor_bytes(ts, es, lastblocklen); present_enc(ts, cxt->userkey); } /* encode the adlen and process */ unsigned long long t_adlen = mlen; unsigned long long i; for(i = 0; i < sizeof(unsigned long long); i++) { ts[STATE_LEN-1-i] ^= t_adlen & 0xff; t_adlen >>= 8; } g(ts); present_enc(ts, cxt->userkey); memcpy(tag, ts, tlen); return SUCCESS; }
void put_timestamp(char* x) { time_t t = time(NULL); copy_bytes((char*)&t, x); int r = rand(); xor_bytes((char*)&r, x); xor_bytes((char*)&r, x + 4); }
/* associated data and nonce length in byte * nlen should be less than 16 bytes and larger than 0 byte; */ int process_ad(ae_cxt* cxt, const byte* ad, unsigned long long adlen, const byte* nonce, unsigned long long nlen) { byte* state = cxt->es; AES_KEY *ekey = cxt->pt_ekey; cxt->ad = (byte*) ad; cxt->adlen = adlen; cxt->nonce = (byte*) nonce; cxt->nlen = nlen; /* process the nonce */ memset(state, 0, STATE_LEN); state[STATE_LEN-nlen-1] = PARAM; memcpy(state+STATE_LEN-nlen, nonce, nlen); //xor_bytes(state, nonce, nlen); // xor to the last nlen bytes pstate2("processing nonce:", NULL); AES_encrypt(state, state, ekey); /* process the middle normal blocks of ad */ unsigned long long i; for(i = 0; i < (unsigned long long)adlen/STATE_LEN; i++){ xor_bytes(state, ad+STATE_LEN*i, STATE_LEN); pstate2("After xoring associated data:", state); pstate2("Enc:", NULL); AES_encrypt(state, state, ekey); } /* process the last block partial block if any */ unsigned long long lastblocklen = adlen % STATE_LEN; if(lastblocklen){ xor_bytes(state, ad+i*STATE_LEN, lastblocklen); pstate2("After processing last partial associated data block:", state); pstate2("Enc:", NULL); AES_encrypt(state, state, ekey); } /* encode the adlen and process */ unsigned long long t_adlen = adlen; for(i = 0; i < sizeof(unsigned long long); i++) { state[STATE_LEN-1-i] ^= t_adlen & 0xff; t_adlen >>= 8; } pstate2("After xoring the length of associated data:", state); g(state); pstate2("After applying g:", state); memcpy(cxt->ts, state, STATE_LEN); pstate2("Enc:", NULL); AES_encrypt(state, state, ekey); g(cxt->ts); pstate2("After applying g to tag state:", cxt->ts); pstate2("Enc:", NULL); AES_encrypt(cxt->ts, cxt->ts, ekey); return SUCCESS; }
int decrypt_final(riv_context_t* ctx, const unsigned char* ciphertext, const unsigned long long ciphertext_length, const unsigned char* header, const unsigned long long header_length, const unsigned char tag[TAGLEN], unsigned char* plaintext) { ALIGN(16) uint8_t iv[TAGLEN]; ALIGN(16) uint8_t iv_prime[TAGLEN]; clhash(&(ctx->prf_context), header, header_length, DOMAIN_1, ciphertext, ciphertext_length, iv); cdms(iv, iv, ctx->expanded_key); xor_bytes(iv, iv, tag, TAGLEN); cdms(iv_prime, iv, ctx->expanded_key); sct_mode(ctx, iv_prime, (const __m128i*)ciphertext, ciphertext_length, (__m128i*)plaintext); clhash(&(ctx->prf_context), header, header_length, DOMAIN_0, plaintext, ciphertext_length, iv_prime); cdms(iv_prime, iv_prime, ctx->expanded_key); return (_mm_testc_si128(load(iv), load(iv_prime)) - 1) | (_mm_testc_si128(load((iv+BLOCKLEN)), load((iv_prime+BLOCKLEN))) - 1); }
void encrypt_final(riv_context_t* ctx, const unsigned char* plaintext, const unsigned long long plaintext_length, const unsigned char* header, const unsigned long long header_length, unsigned char* ciphertext, unsigned char tag[TAGLEN]) { ALIGN(16) uint8_t iv[TAGLEN]; ALIGN(16) uint8_t s[TAGLEN]; clhash(&(ctx->prf_context), header, header_length, DOMAIN_0, plaintext, plaintext_length, iv); cdms(iv, iv, ctx->expanded_key); ALIGN(16) uint8_t iv_prime[TAGLEN]; cdms(iv_prime, iv, ctx->expanded_key); sct_mode(ctx, iv_prime, (const __m128i*)plaintext, plaintext_length, (__m128i*)ciphertext); clhash(&(ctx->prf_context), header, header_length, DOMAIN_1, ciphertext, plaintext_length, s); cdms(s, s, ctx->expanded_key); xor_bytes(tag, s, iv, TAGLEN); }
int encrypt_cbc_AES(const uint8_t *const message, const uint32_t length, const uint8_t *const iv, const AES_KEY *const key, uint8_t *const out) { if(length % 16 != 0) { return -1; // must be of proper size } uint8_t prev[16]; memcpy(prev, iv, 16); // set up init vector uint8_t encbuf[16]; for(uint32_t i = 0; i < length / 16; i++) { xor_bytes(message + i *16, prev, 16, encbuf); // xor in iv encrypt_block_AES(encbuf, prev, key); // encrypt block memcpy(out + i *16, prev, 16); // copy to output } return 0; }
int decrypt_cbc_AES(const uint8_t *const message, const uint32_t length, const uint8_t *const iv, const AES_KEY *const key, uint8_t *const out) { if(length % 16 != 0) { return -1; // must be of proper size } uint8_t prev[16]; memcpy(prev, iv, 16); // set up init vector uint8_t decbuf[16]; for(uint32_t i = 0; i < length / 16; i++) { decrypt_block_AES(message + i *16, decbuf, key); // decrypt block xor_bytes(decbuf, prev, 16, out + i *16); // write to output memcpy(prev, message + i *16, 16); // copy ciphertext for next prev } return 0; }
/*! * @brief Receive a new packet on the given remote endpoint. * @param remote Pointer to the \c Remote instance. * @param packet Pointer to a pointer that will receive the \c Packet data. * @return An indication of the result of processing the transmission request. */ static DWORD packet_receive_named_pipe(Remote *remote, Packet **packet) { DWORD headerBytes = 0, payloadBytesLeft = 0, res; PacketHeader header = { 0 }; LONG bytesRead; BOOL inHeader = TRUE; PUCHAR packetBuffer = NULL; PUCHAR payload = NULL; ULONG payloadLength; NamedPipeTransportContext* ctx = (NamedPipeTransportContext*)remote->transport->ctx; lock_acquire(remote->lock); dprintf("[PIPE PACKET RECEIVE] reading in the header from pipe handle: %p", ctx->pipe); // Read the packet length while (inHeader) { if (!ReadFile(ctx->pipe, ((PUCHAR)&header + headerBytes), sizeof(PacketHeader)-headerBytes, &bytesRead, NULL)) { SetLastError(ERROR_NOT_FOUND); goto out; } headerBytes += bytesRead; if (headerBytes != sizeof(PacketHeader)) { vdprintf("[PIPE] More bytes required"); continue; } inHeader = FALSE; } if (headerBytes != sizeof(PacketHeader)) { dprintf("[PIPE] we didn't get enough header bytes"); goto out; } vdprintf("[PIPE] the XOR key is: %02x%02x%02x%02x", header.xor_key[0], header.xor_key[1], header.xor_key[2], header.xor_key[3]); #ifdef DEBUGTRACE PUCHAR h = (PUCHAR)&header; dprintf("[PIPE] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); #endif // At this point, we might have read in a valid TLV packet, or we might have read in the first chunk of data // from a staged listener after a reconnect. We can figure this out rather lazily by assuming the following: // XOR keys are always 4 bytes that are non-zero. If the higher order byte of the xor key is zero, then it // isn't an XOR Key, instead it's the 4-byte length of the metsrv binary (because metsrv isn't THAT big). if (header.xor_key[3] == 0) { // looks like we have a metsrv instance, time to ignore it. int length = *(int*)&header.xor_key[0]; dprintf("[PIPE] discovered a length header, assuming it's metsrv of length %d", length); int bytesToRead = length - sizeof(PacketHeader) + sizeof(DWORD); char* buffer = (char*)malloc(bytesToRead); read_raw_bytes_to_buffer(ctx, buffer, bytesToRead, &bytesRead); free(buffer); // did something go wrong. if (bytesToRead != bytesRead) { dprintf("[PIPE] Failed to read all bytes when flushing the buffer: %u vs %u", bytesToRead, bytesRead); goto out; } // indicate success, but don't return a packet for processing SetLastError(ERROR_SUCCESS); *packet = NULL; } else { vdprintf("[PIPE] XOR key looks fine, moving on"); // xor the header data xor_bytes(header.xor_key, (PUCHAR)&header + sizeof(header.xor_key), sizeof(PacketHeader) - sizeof(header.xor_key)); #ifdef DEBUGTRACE PUCHAR h = (PUCHAR)&header; dprintf("[PIPE] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); #endif // if we don't have a GUID yet, we need to take the one given in the packet if (is_null_guid(remote->orig_config->session.session_guid)) { memcpy(remote->orig_config->session.session_guid, header.session_guid, sizeof(remote->orig_config->session.session_guid)); } payloadLength = ntohl(header.length) - sizeof(TlvHeader); dprintf("[PIPE] Payload length is %u 0x%08x", payloadLength, payloadLength); DWORD packetSize = sizeof(PacketHeader) + payloadLength; dprintf("[PIPE] total buffer size for the packet is %u 0x%08x", packetSize, packetSize); payloadBytesLeft = payloadLength; // Allocate the payload if (!(packetBuffer = (PUCHAR)malloc(packetSize))) { dprintf("[PIPE] Failed to create the packet buffer"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto out; } dprintf("[PIPE] Allocated packet buffer at %p", packetBuffer); // we're done with the header data, so we need to re-encode it, as the packet decryptor is going to // handle the extraction for us. xor_bytes(header.xor_key, (LPBYTE)&header.session_guid[0], sizeof(PacketHeader) - sizeof(header.xor_key)); // Copy the packet header stuff over to the packet memcpy_s(packetBuffer, sizeof(PacketHeader), (LPBYTE)&header, sizeof(PacketHeader)); payload = packetBuffer + sizeof(PacketHeader); // Read the payload res = read_raw_bytes_to_buffer(ctx, payload, payloadLength, &bytesRead); dprintf("[PIPE] wanted %u read %u", payloadLength, bytesRead); // Didn't finish? if (bytesRead != payloadLength) { dprintf("[PIPE] Failed to get all the payload bytes"); SetLastError(res); goto out; } vdprintf("[PIPE] decrypting packet"); SetLastError(decrypt_packet(remote, packet, packetBuffer, packetSize)); free(packetBuffer); packetBuffer = NULL; } out: res = GetLastError(); // Cleanup if (packetBuffer) { free(packetBuffer); } lock_release(remote->lock); return res; }
/* associated data and nonce length in byte * nlen should be less than 16 bytes and larger than 0 byte; */ int process_ad(ae_cxt* cxt, const byte* ad, unsigned long long adlen, const byte* nonce, unsigned long long nlen) { byte* state = cxt->es; cxt->ad = (byte*) ad; cxt->adlen = adlen; cxt->nonce = (byte*) nonce; cxt->nlen = nlen; /* process the first block */ int ozp = 0; if(adlen < STATE_LEN){ // less than one block memcpy(state, ad, adlen); memset(state+adlen, 0, STATE_LEN-adlen); state[adlen] = 0x80; ozp = 1; // one-zero padding works only if the adlen < 16 } else{ // full first block memcpy(state, ad, STATE_LEN); } /* apply fix0 and the E_k */ int fix0 = state[0] & 0x80; /* test if the MSB is zero */ state[0] &= 0x7f; /* apply the first encryption */ Encode(state, state); /* when fix0 works, apply h */ if(fix0){ word* wd = (word*) state; h(wd[0], wd[1], wd[2], wd[3]); } else{ // do nothing } /* process the middle normal blocks of ad */ unsigned long long i; for(i = 1; i < (unsigned long long)adlen/STATE_LEN; i++){ xor_bytes(state, ad+i*STATE_LEN, STATE_LEN); pstate2("After xoring associated data:", state); Encode(state, state); } /* process the last block partial block if any */ unsigned long long lastblocklen = adlen % STATE_LEN; if((adlen > STATE_LEN) && lastblocklen){ xor_bytes(state, ad+i*STATE_LEN, lastblocklen); state[lastblocklen] ^= 0x80; pstate2("After processing last partial associated data block:", state); Encode(state, state); ozp = 1; } /* process the nonce */ xor_bytes(state, nonce, nlen); /* apply padding to nonce */ if(nlen != STATE_LEN) state[nlen] ^= 0x80; /* apply f1 or f2 to get V */ if(ozp){ // apply f2 word* wd = (word*) state; f2(wd[0], wd[1], wd[2], wd[3]); } else{ // apply f1 word* wd = (word*) state; f1(wd[0], wd[1], wd[2], wd[3]); } pstate2("After applying f1/f2 to state:", state); memcpy(cxt->ts, state, STATE_LEN); Encode(state, state); return SUCCESS; }
/*! * @brief Windows-specific function to receive a new packet via one of the HTTP libs (WinInet or WinHTTP). * @param remote Pointer to the \c Remote instance. * @param packet Pointer to a pointer that will receive the \c Packet data. * @return An indication of the result of processing the transmission request. */ static DWORD packet_receive_http(Remote *remote, Packet **packet) { DWORD headerBytes = 0, payloadBytesLeft = 0, res; Packet *localPacket = NULL; PacketHeader header; LONG bytesRead; BOOL inHeader = TRUE; PUCHAR packetBuffer = NULL; ULONG payloadLength; HttpTransportContext* ctx = (HttpTransportContext*)remote->transport->ctx; HINTERNET hReq; BOOL hRes; DWORD retries = 5; lock_acquire(remote->lock); hReq = ctx->create_req(ctx, TRUE, "PACKET RECEIVE"); if (hReq == NULL) { goto out; } vdprintf("[PACKET RECEIVE HTTP] sending GET"); hRes = ctx->send_req(ctx, hReq, NULL, 0); if (!hRes) { dprintf("[PACKET RECEIVE HTTP] Failed send_req: %d %d", GetLastError(), WSAGetLastError()); SetLastError(ERROR_NOT_FOUND); goto out; } vdprintf("[PACKET RECEIVE HTTP] Waiting to see the response ..."); if (ctx->receive_response && !ctx->receive_response(hReq)) { vdprintf("[PACKET RECEIVE] Failed receive: %d", GetLastError()); SetLastError(ERROR_NOT_FOUND); goto out; } SetLastError(ctx->validate_response(hReq, ctx)); if (GetLastError() != ERROR_SUCCESS) { goto out; } // Read the packet length retries = 3; vdprintf("[PACKET RECEIVE HTTP] Start looping through the receive calls"); while (inHeader && retries > 0) { retries--; if (!ctx->read_response(hReq, (PUCHAR)&header + headerBytes, sizeof(PacketHeader)-headerBytes, &bytesRead)) { dprintf("[PACKET RECEIVE HTTP] Failed HEADER read_response: %d", GetLastError()); SetLastError(ERROR_NOT_FOUND); goto out; } vdprintf("[PACKET RECEIVE NHTTP] Data received: %u bytes", bytesRead); // If the response contains no data, this is fine, it just means the // remote side had nothing to tell us. Indicate this through a // ERROR_EMPTY response code so we can update the timestamp. if (bytesRead == 0) { SetLastError(ERROR_EMPTY); goto out; } headerBytes += bytesRead; if (headerBytes != sizeof(PacketHeader)) { continue; } inHeader = FALSE; } if (headerBytes != sizeof(PacketHeader)) { dprintf("[PACKET RECEIVE HTTP] headerBytes not valid"); SetLastError(ERROR_NOT_FOUND); goto out; } dprintf("[PACKET RECEIVE HTTP] decoding header"); PacketHeader encodedHeader; memcpy(&encodedHeader, &header, sizeof(PacketHeader)); xor_bytes(header.xor_key, (PUCHAR)&header + sizeof(header.xor_key), sizeof(PacketHeader) - sizeof(header.xor_key)); #ifdef DEBUGTRACE PUCHAR h = (PUCHAR)&header; vdprintf("[HTTP] Packet header: [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X] [0x%02X 0x%02X 0x%02X 0x%02X]", h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19], h[20], h[21], h[22], h[23], h[24], h[25], h[26], h[27], h[28], h[29], h[30], h[31]); #endif payloadLength = ntohl(header.length) - sizeof(TlvHeader); vdprintf("[REC HTTP] Payload length is %d", payloadLength); DWORD packetSize = sizeof(PacketHeader) + payloadLength; vdprintf("[REC HTTP] total buffer size for the packet is %d", packetSize); payloadBytesLeft = payloadLength; // Allocate the payload if (!(packetBuffer = (PUCHAR)malloc(packetSize))) { dprintf("[REC HTTP] Failed to create the packet buffer"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto out; } dprintf("[REC HTTP] Allocated packet buffer at %p", packetBuffer); // Copy the packet header stuff over to the packet memcpy_s(packetBuffer, sizeof(PacketHeader), (LPBYTE)&encodedHeader, sizeof(PacketHeader)); LPBYTE payload = packetBuffer + sizeof(PacketHeader); // Read the payload retries = payloadBytesLeft; while (payloadBytesLeft > 0 && retries > 0) { vdprintf("[PACKET RECEIVE HTTP] reading more data from the body..."); retries--; if (!ctx->read_response(hReq, payload + payloadLength - payloadBytesLeft, payloadBytesLeft, &bytesRead)) { dprintf("[PACKET RECEIVE] Failed BODY read_response: %d", GetLastError()); SetLastError(ERROR_NOT_FOUND); goto out; } if (!bytesRead) { vdprintf("[PACKET RECEIVE HTTP] no bytes read, bailing out"); SetLastError(ERROR_NOT_FOUND); goto out; } vdprintf("[PACKET RECEIVE HTTP] bytes read: %u", bytesRead); payloadBytesLeft -= bytesRead; } // Didn't finish? if (payloadBytesLeft) { goto out; } #ifdef DEBUGTRACE h = (PUCHAR)&header.session_guid[0]; dprintf("[HTTP] Packet Session GUID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8], h[9], h[10], h[11], h[12], h[13], h[14], h[15]); #endif if (is_null_guid(header.session_guid) || memcmp(remote->orig_config->session.session_guid, header.session_guid, sizeof(header.session_guid)) == 0) { dprintf("[HTTP] Session GUIDs match (or packet guid is null), decrypting packet"); SetLastError(decrypt_packet(remote, packet, packetBuffer, packetSize)); } else { dprintf("[HTTP] Session GUIDs don't match, looking for a pivot"); PivotContext* pivotCtx = pivot_tree_find(remote->pivot_sessions, header.session_guid); if (pivotCtx != NULL) { dprintf("[HTTP] Pivot found, dispatching packet on a thread (to avoid main thread blocking)"); SetLastError(pivot_packet_dispatch(pivotCtx, packetBuffer, packetSize)); // mark this packet buffer as NULL as the thread will clean it up packetBuffer = NULL; *packet = NULL; } else { dprintf("[HTTP] Session GUIDs don't match, can't find pivot!"); } } out: res = GetLastError(); dprintf("[HTTP] Cleaning up"); SAFE_FREE(packetBuffer); // Cleanup on failure if (res != ERROR_SUCCESS) { SAFE_FREE(localPacket); } if (hReq) { ctx->close_req(hReq); } lock_release(remote->lock); dprintf("[HTTP] Packet receive finished"); return res; }
int rsa_pss_verify(RSA_PUBLIC_KEY *key, uint8_t *sig, size_t siglen, uint8_t *message, size_t mlen, int *valid) { if(key == NULL || sig == NULL || message == NULL || valid == NULL) { return -1; } const size_t emlen = (key->bits - 2) / 8 + 1; const size_t hlen = 32; const size_t slen = hlen; SHA256_CTX ctx; uint8_t hash[hlen]; uint8_t zeroes[8]; uint8_t *em = NULL; uint8_t *mask = NULL; bignum em_bn = BN_ZERO; bignum s_bn = BN_ZERO; int ret; *valid = 0; if((em = malloc(emlen)) == NULL) { return MALLOC_FAIL; } if((mask = malloc(emlen - hlen - 1)) == NULL) { ret = MALLOC_FAIL; goto err; } if((ret = os2ip(&s_bn, sig, siglen)) != 0) { /* cleanup is non-necessary here, but no harm */ goto err; } if((ret = rsa_encrypt(key, &s_bn, &em_bn)) != 0) { goto err; } if((ret = i2osp(em, emlen, &em_bn)) != 0) { goto err; } mgf1_sha256(&em[emlen - hlen - 1], hlen, emlen - hlen - 1, mask); xor_bytes(em, mask, emlen - hlen - 1, em); sha256_init(&ctx); sha256_update(&ctx, message, mlen); sha256_final(&ctx, hash); memset(zeroes, 0x00, 8); sha256_init(&ctx); sha256_update(&ctx, zeroes, 8); sha256_update(&ctx, hash, hlen); sha256_update(&ctx, &em[emlen - hlen - slen - 1], slen); sha256_final(&ctx, hash); xor_bytes(&em[emlen - hlen - 1], hash, hlen, &em[emlen - hlen - 1]); em[emlen - hlen - slen - 2] ^= 0x01; em[emlen - 1] ^= 0xbc; em[0] &= ((uint8_t) 0xff) >> (emlen * 8 - (key->bits - 2)); memset(&em[emlen - hlen - slen - 1], 0x00, slen); size_t i; uint8_t val = 0; for(i = 0; i < emlen; i++) { val |= (em[i]); } if(val) { *valid = 0; } else { *valid = 1; } ret = 0; err: memsets(&ctx, 0x00, sizeof(SHA256_CTX)); memsets(hash, 0x00, hlen); if(em) zfree(em, emlen); if(mask) zfree(mask, emlen - hlen - 1); bnu_free(&em_bn); bnu_free(&s_bn); return ret; }
/* * plaintext, message length in byte, ciphertext, associated data, and associated data length in byte tag, and tag length in byte */ int ae_encrypt(ae_cxt* cxt, byte* pt, unsigned long long mlen, byte* ct, byte* tag, unsigned long long tlen, int enc_dec) { cxt->pt = pt; cxt->ptlen = mlen; cxt->ct = ct; cxt->ctlen = mlen; cxt->tag = tag; cxt->tlen = tlen; byte* es = cxt->es; byte* ts = cxt->ts; word* wd = (word*) ts; if(mlen != 0){ g2(wd[0], wd[1], wd[2], wd[3]); Encode(cxt->ts, cxt->ts); } else{ g1(wd[0], wd[1], wd[2], wd[3]); Encode(cxt->ts, cxt->ts); memcpy(tag, ts, tlen); return SUCCESS; } unsigned long long pc = 0; while((pc + STATE_LEN) < mlen){ if(enc_dec == ENC){ // encryption xor_bytes(es, pt+pc, STATE_LEN); pstate2("After xoring message block:", es); memcpy(ct+pc, es, STATE_LEN); } else{ // decryption xor_bytes2(pt+pc, ct+pc, es, STATE_LEN); pstate2("After xoring ciphertext block:", es); memcpy(es, ct+pc, STATE_LEN); } xor_bytes(ts, es, STATE_LEN); Encode(ts, ts); /* apply fix1 */ es[0] |= 0x80; pstate2("After applying fix1:", es); Encode(es, es); pc += STATE_LEN; } /* process the last block */ unsigned long long lastblocklen = mlen - pc; if(enc_dec == ENC){ // encryption xor_bytes(es, pt+pc, lastblocklen); pstate2("After xoring last partial message block:", es); memcpy(ct+pc, es, lastblocklen); } else{ // decryption xor_bytes2(pt+pc, ct+pc, es, lastblocklen); pstate2("After xoring last partial ciphertext block:", es); memcpy(es, ct+pc, lastblocklen); } xor_bytes(ts, es, lastblocklen); pstate2("tag state:", ts); if(lastblocklen != STATE_LEN){ // apply f2 /* apply padding only when last message block is not full */ ts[lastblocklen] ^= 0x80; word* wd = (word*) ts; f2(wd[0], wd[1], wd[2], wd[3]); } else{ // apply f1 word* wd = (word*) ts; f1(wd[0], wd[1], wd[2], wd[3]); } pstate2("After applying f1/f2:", ts); Encode(ts, ts); memcpy(tag, ts, tlen); return SUCCESS; }
int rsa_oaep_decrypt(RSA_KEY *key, uint8_t *ctext, size_t clen, uint8_t *out, size_t outlen) { if(key == NULL || ctext == NULL || out == NULL) { return -1; } const size_t k = (key->bits - 1) / 8 + 1; const size_t hlen = 32; bignum c_bn = BN_ZERO; bignum m_bn = BN_ZERO; uint8_t *em = NULL; uint8_t *db = NULL; uint8_t *mask = NULL; uint8_t seed[hlen]; size_t message_start; int ret; /* nothing critical yet */ if((ret = os2ip(&c_bn, ctext, clen)) != 0) { return ret; } /* now sensitive information is contained in our buffers, so we have * to clean up */ if((ret = rsa_decrypt(key, &c_bn, &m_bn)) != 0) { goto err; } if((em = malloc(k)) == NULL) { ret = MALLOC_FAIL; goto err; } if((ret = i2osp(em, k, &m_bn)) != 0) { goto err; } db = em + hlen + 1; if((mask = malloc(k - hlen - 1)) == NULL) { ret = MALLOC_FAIL; goto err; } /* calculate seed mask = MGF1(maskedDB, k - hlen - 1) */ mgf1_sha256(db, k - hlen - 1, hlen, mask); /* calculate seed */ xor_bytes(em + 1, mask, hlen, seed); /* calculate dbMask */ mgf1_sha256(seed, hlen, k - hlen - 1, mask); /* unmask db */ xor_bytes(db, mask, k - hlen - 1, db); /* find the start of the message */ for(message_start = hlen; message_start < k - hlen - 1 && db[message_start] == 0x00; message_start++) {} uint8_t valid = 0; valid |= memcmp_ct(db, lhash, 32); valid |= em[0]; valid |= !(message_start != k - hlen - 1 && db[message_start] == 1); /* if valid is non-zero this is not a valid message */ if(valid != 0) { ret = CRYPTOGRAPHY_ERROR; goto err; } message_start++; /* prevent buffer overflows */ if(outlen < k - hlen - 1 - message_start) { ret = TOO_SHORT; goto err; } memcpy(out, &db[message_start], k - hlen - 1 - message_start); ret = 0; err: ret = ret == 0 ? bnu_free(&c_bn) : ret; ret = ret == 0 ? bnu_free(&m_bn) : ret; if(em) zfree(em, k); if(mask) zfree(mask, k - hlen - 1); memsets(seed, 0x00, hlen); return ret; }
int rsa_pss_sign(RSA_KEY *key, uint8_t *message, size_t mlen, uint8_t *out, size_t outlen) { if(key == NULL || message == NULL || out == NULL) { return -1; } const size_t k = (key->bits - 1) / 8 + 1; const size_t emlen = (key->bits - 2) / 8 + 1; const size_t hlen = 32; const size_t slen = hlen; SHA256_CTX ctx; uint8_t mhash[hlen]; uint8_t salt[slen]; uint8_t zeroes[8]; uint8_t *em = NULL; bignum em_bn = BN_ZERO; bignum s_bn = BN_ZERO; int ret; if(outlen < k) { /* avoid buffer overflows */ return TOO_SHORT; } if(emlen < hlen + slen + 2) { /* key too small to sign */ return CRYPTOGRAPHY_ERROR; } /* allocate space for em */ if((em = malloc(emlen)) == NULL) { return MALLOC_FAIL; } /* generate salt, as we can still exit without cleanup if this fails */ if(cs_rand(salt, slen) != 0) { return CRYPTOGRAPHY_ERROR; } sha256_init(&ctx); sha256_update(&ctx, message, mlen); sha256_final(&ctx, mhash); /* calculate H = sha256(0x00 00 00 00 00 00 00 00 || mhash || salt) */ memset(zeroes, 0x00, 8); sha256_init(&ctx); sha256_update(&ctx, zeroes, 8); sha256_update(&ctx, mhash, hlen); sha256_update(&ctx, salt, slen); sha256_final(&ctx, &em[emlen - hlen - 1]); mgf1_sha256(&em[emlen - hlen - 1], hlen, emlen - hlen - 1, em); /* xor in 0x01 and salt */ em[emlen - slen - hlen - 2] ^= 0x01; xor_bytes(&em[emlen - slen - hlen - 1], salt, slen, &em[emlen - slen - hlen - 1]); em[emlen - 1] = 0xbc; em[0] &= ((uint8_t) 0xff) >> (8 * emlen - (key->bits - 2)); if((ret = os2ip(&em_bn, em, emlen)) != 0) { goto err; } if((ret = rsa_decrypt(key, &em_bn, &s_bn)) != 0) { goto err; } if((ret = i2osp(out, outlen, &s_bn)) != 0) { goto err; } ret = 0; err: memsets(mhash, 0, hlen); memsets(salt, 0, slen); memsets(&ctx, 0, sizeof(SHA256_CTX)); bnu_free(&s_bn); bnu_free(&em_bn); if(em) zfree(em, emlen); return ret; }
int rsa_oaep_encrypt(RSA_PUBLIC_KEY *key, uint8_t *message, size_t mlen, uint8_t *out, size_t outlen) { if(key == NULL || message == NULL || out == NULL) { return -1; } const size_t k = (key->bits - 1) / 8 + 1; const size_t hlen = 32; uint8_t seed[hlen]; uint8_t *mask; uint8_t *em; uint8_t *db; bignum m_bn; bignum c_bn; int ret; /* message is too long to encrypt */ if(k - 2 * hlen - 2 < mlen) { return TOO_LONG; } /* output buffer is too small */ if(outlen < k) { return TOO_SHORT; } /* do stuff involving the masks first, as in case of error it does not * need to be kept secure */ if(cs_rand(seed, hlen) != 0) { return CRYPTOGRAPHY_ERROR; } if((mask = malloc(k - hlen - 1)) == NULL) { return MALLOC_FAIL; } /* calculate dbMask = MGF(seed, k - hLen - 1) */ mgf1_sha256(seed, hlen, k - hlen - 1, mask); /* now initialize the string to be encrypted */ if((em = malloc(k)) == NULL) { return MALLOC_FAIL; } /* from now on we have to clean up memory after any failures */ /* em[hlen:] is all DB = lhash || PS || 0x01 || M */ db = em + hlen + 1; memcpy(db, lhash, hlen); /* PS is a padding string of zeroes */ memset(db + hlen, 0x00, k - 2 * hlen - mlen - 2); /* there is then one byte of value 0x01 */ db[k - 2 - hlen - mlen] = 0x01; /* then message */ memcpy(&db[k - hlen - 1 - mlen], message, mlen); /* now apply the mask to it */ xor_bytes(db, mask, k - hlen - 1, db); /* now we can repurpose mask to encode the seed mask */ mgf1_sha256(db, k - hlen - 1, hlen, mask); /* xor it into em */ xor_bytes(seed, mask, hlen, em + 1); em[0] = 0x00; m_bn = BN_ZERO; c_bn = BN_ZERO; /* now convert to a big integer */ if((ret = os2ip(&m_bn, em, k)) != 0) { goto err; } /* encrypt */ if((ret = rsa_encrypt(key, &m_bn, &c_bn)) != 0) { goto err; } /* convert back */ if((ret = i2osp(out, outlen, &c_bn)) != 0) { goto err; } /* encryption is officially done, clean up */ ret = 0; err: /* free mask and em, zero seed */ zfree(mask, k - hlen - 1); zfree(em, k - 1); memsets(seed, 0x00, hlen); /* free the bignums */ /* an error here is still an error as it is a possible leak of * sensitive data */ ret = ret == 0 ? bnu_free(&m_bn) : ret; ret = ret == 0 ? bnu_free(&c_bn) : ret; return ret; }
/* * plaintext, message length in byte, ciphertext, associated data, and associated data length in byte tag, and tag length in byte */ int ae_encrypt(ae_cxt* cxt, byte* pt, unsigned long long mlen, byte* ct, byte* tag, unsigned long long tlen, int enc_dec) { cxt->pt = pt; cxt->ptlen = mlen; cxt->ct = ct; cxt->ctlen = mlen; cxt->tag = tag; cxt->tlen = tlen; byte* es = cxt->es; byte* ts = cxt->ts; AES_KEY *ekey = cxt->pt_ekey; unsigned long long pc = 0; while((pc + STATE_LEN) < mlen){ if(enc_dec == ENC){ // encryption xor_bytes(es, pt+pc, STATE_LEN); pstate2("After xoring message block:", es); memcpy(ct+pc, es, STATE_LEN); } else{ // decryption xor_bytes2(pt+pc, ct+pc, es, STATE_LEN); pstate2("After xoring ciphertext block:", es); memcpy(es, ct+pc, STATE_LEN); } xor_bytes(ts, es, STATE_LEN); pstate2("tag state:", ts); pstate2("Enc:", NULL); AES_encrypt(ts, ts, ekey); /* apply fix1 */ es[0] |= 0x80; pstate2("After applying fix1:", es); pstate2("Enc:", NULL); AES_encrypt(es, es, ekey); pc += STATE_LEN; } /* process the last block */ unsigned long long lastblocklen = mlen - pc; if(lastblocklen > 0){ if(enc_dec == ENC){ // encryption xor_bytes(es, pt+pc, lastblocklen); pstate2("After xoring last partial message block:", es); memcpy(ct+pc, es, lastblocklen); } else{ // decryption xor_bytes2(pt+pc, ct+pc, es, lastblocklen); pstate2("After xoring last partial ciphertext block:", es); memcpy(es, ct+pc, lastblocklen); } xor_bytes(ts, es, lastblocklen); pstate2("tag state:", ts); pstate2("Enc:", NULL); AES_encrypt(ts, ts, ekey); } /* encode the adlen and process */ unsigned long long t_adlen = mlen; unsigned long long i; for(i = 0; i < sizeof(unsigned long long); i++) { ts[STATE_LEN-1-i] ^= t_adlen & 0xff; t_adlen >>= 8; } pstate2("After xoring the legnth of message:", ts); g(ts); pstate2("After applying g:", ts); pstate2("Enc:", NULL); AES_encrypt(ts, ts, ekey); memcpy(tag, ts, tlen); return SUCCESS; }
/// @param *data : returns the decoded information as a data_t * static int decode_xc0324_message(r_device *decoder, bitbuffer_t *bitbuffer, unsigned row, uint16_t bitpos, const int latest_event, data_t **data) { uint8_t b[XC0324_MESSAGE_BYTELEN]; char id [4] = {0}; double temperature; uint8_t flags; uint8_t chksum; // == 0x00 for a good message // Extract the message bitbuffer_extract_bytes(bitbuffer, row, bitpos, b, XC0324_MESSAGE_BITLEN); // Examine the chksum and bail out now if not OK to save time // b[5] is a check byte, the XOR of bytes 0-4. // ie a checksum where the sum is "binary add no carry" // Effectively, each bit of b[5] is the parity of the bits in the // corresponding position of b[0] to b[4] // NB : b[0] ^ b[1] ^ b[2] ^ b[3] ^ b[4] ^ b[5] == 0x00 for a clean message chksum = xor_bytes(b, 6); if (chksum != 0x00) { if (decoder->verbose == 1) { // Output the "bad" message (only for message level deciphering!) decoder_output_bitrowf(decoder, b, XC0324_MESSAGE_BITLEN, "chksum = 0x%02X not 0x00 <- XC0324:vv row %d bit %d", chksum, row, bitpos); } return 0; // No message was able to be decoded } // Extract the id as hex string snprintf(id, 3, "%02X", b[1]); // Decode temperature (b[2]), plus 1st 4 bits b[3], LSB first order! // Tenths of degrees C, offset from the minimum possible (-40.0 degrees) uint16_t temp = ((uint16_t)(reverse8(b[3]) & 0x0f) << 8) | reverse8(b[2]) ; temperature = (temp / 10.0) - 40.0 ; //Unknown byte, constant as 0x80 in all my data // ??maybe battery status?? flags = b[4]; // Create the data structure, ready for the decoder_output_data function. // Separate production output (decoder->verbose == 0) // from (simulated) deciphering stage output (decoder->verbose > 0) if (!decoder->verbose) { // production output *data = data_make( "model", "Device Type", DATA_STRING, "Digitech XC0324", "id", "ID", DATA_STRING, id, "temperature_C", "Temperature C", DATA_FORMAT, "%.1f", DATA_DOUBLE, temperature, "flags", "Constant ?", DATA_INT, flags, "mic", "Integrity", DATA_STRING, "CHECKSUM", NULL); } // Output (simulated) message level deciphering information.. if (decoder->verbose == 1) { decoder_output_bitrowf(decoder, b, XC0324_MESSAGE_BITLEN, "Temp was %4.1f <- XC0324:vv row %03d bit %03d", temperature, row, bitpos); } // Output "finished deciphering" reference values for future regression tests. if ((decoder->verbose == 3) & (latest_event == 0)) { //info from this first successful message is enough decoder_output_messagef(decoder, "XC0324:vvvv Reference -> Temperature %4.1f C; sensor id %s", temperature, id); } return 1; // Message successfully decoded }
/*! * @brief Transmit a packet via SSL _and_ destroy it. * @param remote Pointer to the \c Remote instance. * @param packet Pointer to the \c Packet that is to be sent. * @param completion Pointer to the completion routines to process. * @return An indication of the result of processing the transmission request. * @remark This uses an SSL-encrypted TCP channel, and does not imply the use of HTTPS. */ DWORD packet_transmit_via_ssl(Remote* remote, Packet* packet, PacketRequestCompletion* completion) { CryptoContext* crypto; Tlv requestId; DWORD res; DWORD idx; TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx; lock_acquire(remote->lock); // If the packet does not already have a request identifier, create one for it if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestId) != ERROR_SUCCESS) { DWORD index; CHAR rid[32]; rid[sizeof(rid)-1] = 0; for (index = 0; index < sizeof(rid)-1; index++) { rid[index] = (rand() % 0x5e) + 0x21; } packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid); } do { // If a completion routine was supplied and the packet has a request // identifier, insert the completion routine into the list if ((completion) && (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestId) == ERROR_SUCCESS)) { packet_add_completion_handler((LPCSTR)requestId.buffer, completion); } // If the endpoint has a cipher established and this is not a plaintext // packet, we encrypt if ((crypto = remote_get_cipher(remote)) && (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_REQUEST) && (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_RESPONSE)) { ULONG origPayloadLength = packet->payloadLength; PUCHAR origPayload = packet->payload; // Encrypt if ((res = crypto->handlers.encrypt(crypto, packet->payload, packet->payloadLength, &packet->payload, &packet->payloadLength)) != ERROR_SUCCESS) { SetLastError(res); break; } // Destroy the original payload as we no longer need it free(origPayload); // Update the header length packet->header.length = htonl(packet->payloadLength + sizeof(TlvHeader)); } dprintf("[PACKET] New xor key for sending"); packet->header.xor_key = rand_xor_key(); // before transmission, xor the whole lot, starting with the body xor_bytes(packet->header.xor_key, (LPBYTE)packet->payload, packet->payloadLength); // then the header xor_bytes(packet->header.xor_key, (LPBYTE)&packet->header.length, 8); // be sure to switch the xor header before writing packet->header.xor_key = htonl(packet->header.xor_key); idx = 0; while (idx < sizeof(packet->header)) { // Transmit the packet's header (length, type) res = SSL_write( ctx->ssl, (LPCSTR)(&packet->header) + idx, sizeof(packet->header) - idx ); if (res <= 0) { dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx); break; } idx += res; } if (res < 0) { break; } idx = 0; while (idx < packet->payloadLength) { // Transmit the packet's payload (length, type) res = SSL_write( ctx->ssl, packet->payload + idx, packet->payloadLength - idx ); if (res < 0) { break; } idx += res; } if (res < 0) { dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx); break; } SetLastError(ERROR_SUCCESS); } while (0); res = GetLastError(); // Destroy the packet packet_destroy(packet); lock_release(remote->lock); return res; }
/*! * @brief Receive a new packet on the given remote endpoint. * @param remote Pointer to the \c Remote instance. * @param packet Pointer to a pointer that will receive the \c Packet data. * @return An indication of the result of processing the transmission request. */ static DWORD packet_receive_via_ssl(Remote *remote, Packet **packet) { DWORD headerBytes = 0, payloadBytesLeft = 0, res; CryptoContext *crypto = NULL; Packet *localPacket = NULL; PacketHeader header; LONG bytesRead; BOOL inHeader = TRUE; PUCHAR payload = NULL; ULONG payloadLength; TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx; lock_acquire(remote->lock); do { // Read the packet length while (inHeader) { if ((bytesRead = SSL_read(ctx->ssl, ((PUCHAR)&header + headerBytes), sizeof(PacketHeader)-headerBytes)) <= 0) { if (!bytesRead) { SetLastError(ERROR_NOT_FOUND); } if (bytesRead < 0) { dprintf("[PACKET] receive header failed with error code %d. SSLerror=%d, WSALastError=%d\n", bytesRead, SSL_get_error(ctx->ssl, bytesRead), WSAGetLastError()); SetLastError(ERROR_NOT_FOUND); } break; } headerBytes += bytesRead; if (headerBytes != sizeof(PacketHeader)) { continue; } inHeader = FALSE; } if (headerBytes != sizeof(PacketHeader)) { break; } header.xor_key = ntohl(header.xor_key); // xor the header data xor_bytes(header.xor_key, &header.length, 8); // Initialize the header header.length = ntohl(header.length); // use TlvHeader size here, because the length doesn't include the xor byte payloadLength = header.length - sizeof(TlvHeader); payloadBytesLeft = payloadLength; // Allocate the payload if (!(payload = (PUCHAR)malloc(payloadLength))) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); break; } // Read the payload while (payloadBytesLeft > 0) { if ((bytesRead = SSL_read(ctx->ssl, payload + payloadLength - payloadBytesLeft, payloadBytesLeft)) <= 0) { if (GetLastError() == WSAEWOULDBLOCK) { continue; } if (!bytesRead) { SetLastError(ERROR_NOT_FOUND); } if (bytesRead < 0) { dprintf("[PACKET] receive payload of length %d failed with error code %d. SSLerror=%d\n", payloadLength, bytesRead, SSL_get_error(ctx->ssl, bytesRead)); SetLastError(ERROR_NOT_FOUND); } break; } payloadBytesLeft -= bytesRead; } // Didn't finish? if (payloadBytesLeft) { break; } xor_bytes(header.xor_key, payload, payloadLength); // Allocate a packet structure if (!(localPacket = (Packet *)malloc(sizeof(Packet)))) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); break; } memset(localPacket, 0, sizeof(Packet)); // If the connection has an established cipher and this packet is not // plaintext, decrypt if ((crypto = remote_get_cipher(remote)) && (packet_get_type(localPacket) != PACKET_TLV_TYPE_PLAIN_REQUEST) && (packet_get_type(localPacket) != PACKET_TLV_TYPE_PLAIN_RESPONSE)) { ULONG origPayloadLength = payloadLength; PUCHAR origPayload = payload; // Decrypt if ((res = crypto->handlers.decrypt(crypto, payload, payloadLength, &payload, &payloadLength)) != ERROR_SUCCESS) { SetLastError(res); break; } // We no longer need the encrypted payload free(origPayload); } localPacket->header.length = header.length; localPacket->header.type = header.type; localPacket->payload = payload; localPacket->payloadLength = payloadLength; *packet = localPacket; SetLastError(ERROR_SUCCESS); } while (0); res = GetLastError(); // Cleanup on failure if (res != ERROR_SUCCESS) { if (payload) { free(payload); } if (localPacket) { free(localPacket); } } lock_release(remote->lock); return res; }