static inline bool do_check64 (size_t i, const Elf64_auxv_t (*a64)[], uint_fast8_t *elfdata) { /* The AUXV pointer might not even be naturally aligned for 64-bit data, because note payloads in a core file are not aligned. */ uint64_t type = read_8ubyte_unaligned_noncvt (&(*a64)[i].a_type); uint64_t val = read_8ubyte_unaligned_noncvt (&(*a64)[i].a_un.a_val); if (type == BE64 (PROBE_TYPE) && val == BE64 (PROBE_VAL64)) { *elfdata = ELFDATA2MSB; return true; } if (type == LE64 (PROBE_TYPE) && val == LE64 (PROBE_VAL64)) { *elfdata = ELFDATA2LSB; return true; } return false; }
/* Examine an auxv data block and determine its format. Return true iff we figured it out. */ static bool auxv_format_probe (const void *auxv, size_t size, uint_fast8_t *elfclass, uint_fast8_t *elfdata) { const union { char buf[size]; Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)]; Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)]; } *u = auxv; inline bool check64 (size_t i) { /* The AUXV pointer might not even be naturally aligned for 64-bit data, because note payloads in a core file are not aligned. */ uint64_t type = read_8ubyte_unaligned_noncvt (&u->a64[i].a_type); uint64_t val = read_8ubyte_unaligned_noncvt (&u->a64[i].a_un.a_val); if (type == BE64 (PROBE_TYPE) && val == BE64 (PROBE_VAL64)) { *elfdata = ELFDATA2MSB; return true; } if (type == LE64 (PROBE_TYPE) && val == LE64 (PROBE_VAL64)) { *elfdata = ELFDATA2LSB; return true; } return false; }
// Initializes IV and whitening values for sector encryption/decryption in CBC mode. // IMPORTANT: This function has been deprecated (legacy). static void InitSectorIVAndWhitening (unsigned __int64 unitNo, int blockSize, unsigned __int32 *iv, unsigned __int64 *ivSeed, unsigned __int32 *whitening) { /* IMPORTANT: This function has been deprecated (legacy) */ unsigned __int64 iv64[4]; unsigned __int32 *iv32 = (unsigned __int32 *) iv64; iv64[0] = ivSeed[0] ^ LE64(unitNo); iv64[1] = ivSeed[1] ^ LE64(unitNo); iv64[2] = ivSeed[2] ^ LE64(unitNo); if (blockSize == 16) { iv64[3] = ivSeed[3] ^ LE64(unitNo); } iv[0] = iv32[0]; iv[1] = iv32[1]; switch (blockSize) { case 16: // 128-bit block iv[2] = iv32[2]; iv[3] = iv32[3]; whitening[0] = LE32( crc32int ( &iv32[4] ) ^ crc32int ( &iv32[7] ) ); whitening[1] = LE32( crc32int ( &iv32[5] ) ^ crc32int ( &iv32[6] ) ); break; case 8: // 64-bit block whitening[0] = LE32( crc32int ( &iv32[2] ) ^ crc32int ( &iv32[5] ) ); whitening[1] = LE32( crc32int ( &iv32[3] ) ^ crc32int ( &iv32[4] ) ); break; default: GST_THROW_FATAL_EXCEPTION; } }
/* * Helper routine to bridge to packJPG C++ lib, without changing packJPG itself. */ size_t packjpg_filter_process(uchar_t *in_buf, size_t len, uchar_t **out_buf) { unsigned int len1; uchar_t *pos; /* * Workaround for packJPG limitation, not a bug per se. Images created with * Polaroid cameras appear to have some weird huffman data in the middle which * appears not to be interpreted by any image viewer/editor. This data gets * stripped by packJPG. * So the restored images will be visually correct, but, will be smaller than the * original. So we need to look at the Exif Manufacturer tag for 'Polaroid' and * skip those images. This should be within the first 512 bytes of the * file (really...?) so we do a simple buffer scan without trying to parse Exif * data. */ pos = (uchar_t *)memchr(in_buf, 'P', 512); while (pos) { if (LE64(U64_P(pos)) == POLAROID_LE) return (0); pos++; pos = (uchar_t *)memchr(pos, 'P', 512); } pjglib_init_streams(in_buf, 1, len, *out_buf, 1); len1 = len; if (!pjglib_convert_stream2mem(out_buf, &len1, NULL)) return (0); if (len1 == len) return (0); return (len1); }
SEXP LE_integer64(SEXP e1_, SEXP e2_, SEXP ret_){ long long i, n = LENGTH(ret_); long long i1, n1 = LENGTH(e1_); long long i2, n2 = LENGTH(e2_); long long * e1 = (long long *) REAL(e1_); long long * e2 = (long long *) REAL(e2_); Rboolean * ret = (Rboolean *) LOGICAL(ret_); mod_iterate(n1, n2, i1, i2) { LE64(e1[i1],e2[i2],ret[i]) } return ret_; }
/* Examine an auxv data block and determine its format. Return true iff we figured it out. */ static bool auxv_format_probe (const void *auxv, size_t size, uint_fast8_t *elfclass, uint_fast8_t *elfdata) { const union { char buf[size]; Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)]; Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)]; } *u = auxv; inline bool check64 (size_t i) { if (u->a64[i].a_type == BE64 (PROBE_TYPE) && u->a64[i].a_un.a_val == BE64 (PROBE_VAL64)) { *elfdata = ELFDATA2MSB; return true; } if (u->a64[i].a_type == LE64 (PROBE_TYPE) && u->a64[i].a_un.a_val == LE64 (PROBE_VAL64)) { *elfdata = ELFDATA2LSB; return true; } return false; } inline bool check32 (size_t i) { if (u->a32[i].a_type == BE32 (PROBE_TYPE) && u->a32[i].a_un.a_val == BE32 (PROBE_VAL32)) { *elfdata = ELFDATA2MSB; return true; } if (u->a32[i].a_type == LE32 (PROBE_TYPE) && u->a32[i].a_un.a_val == LE32 (PROBE_VAL32)) { *elfdata = ELFDATA2LSB; return true; } return false; } for (size_t i = 0; i < size / sizeof (Elf64_auxv_t); ++i) { if (check64 (i)) { *elfclass = ELFCLASS64; return true; } if (check32 (i * 2) || check32 (i * 2 + 1)) { *elfclass = ELFCLASS32; return true; } } return false; }
static int report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, Dwfl *dwfl, GElf_Addr r_debug_vaddr, Dwfl_Memory_Callback *memory_callback, void *memory_callback_arg) { /* Skip r_version, to aligned r_map field. */ GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass); void *buffer = NULL; size_t buffer_available = 0; inline int release_buffer (int result) { if (buffer != NULL) (void) (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0, memory_callback_arg); return result; } GElf_Addr addrs[4]; inline bool read_addrs (GElf_Addr vaddr, size_t n) { size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read. */ /* Read a new buffer if the old one doesn't cover these words. */ if (buffer == NULL || vaddr < read_vaddr || vaddr - read_vaddr + nb > buffer_available) { release_buffer (0); read_vaddr = vaddr; int segndx = INTUSE(dwfl_addrsegment) (dwfl, vaddr, NULL); if (unlikely (segndx < 0) || unlikely (! (*memory_callback) (dwfl, segndx, &buffer, &buffer_available, vaddr, nb, memory_callback_arg))) return true; } const union { Elf32_Addr a32[n]; Elf64_Addr a64[n]; } *in = vaddr - read_vaddr + buffer; if (elfclass == ELFCLASS32) { if (elfdata == ELFDATA2MSB) for (size_t i = 0; i < n; ++i) addrs[i] = BE32 (in->a32[i]); else for (size_t i = 0; i < n; ++i) addrs[i] = LE32 (in->a32[i]); } else { if (elfdata == ELFDATA2MSB) for (size_t i = 0; i < n; ++i) addrs[i] = BE64 (in->a64[i]); else for (size_t i = 0; i < n; ++i) addrs[i] = LE64 (in->a64[i]); } return false; }
// Optimized for encryption algorithms supporting intra-data-unit parallelization static void EncryptBufferXTSParallel (unsigned __int8 *buffer, TC_LARGEST_COMPILER_UINT length, const UINT64_STRUCT *startDataUnitNo, unsigned int startCipherBlockNo, unsigned __int8 *ks, unsigned __int8 *ks2, int cipher) { unsigned __int8 finalCarry; unsigned __int8 whiteningValues [ENCRYPTION_DATA_UNIT_SIZE]; unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK]; unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK]; unsigned __int64 *whiteningValuesPtr64 = (unsigned __int64 *) whiteningValues; unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; unsigned __int64 *bufPtr = (unsigned __int64 *) buffer; unsigned __int64 *dataUnitBufPtr; unsigned int startBlock = startCipherBlockNo, endBlock, block; unsigned __int64 *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1; TC_LARGEST_COMPILER_UINT blockCount, dataUnitNo; /* The encrypted data unit number (i.e. the resultant ciphertext block) is to be multiplied in the finite field GF(2^128) by j-th power of n, where j is the sequential plaintext/ciphertext block number and n is 2, a primitive element of GF(2^128). This can be (and is) simplified and implemented as a left shift of the preceding whitening value by one bit (with carry propagating). In addition, if the shift of the highest byte results in a carry, 135 is XORed into the lowest byte. The value 135 is derived from the modulus of the Galois Field (x^128+x^7+x^2+x+1). */ // Convert the 64-bit data unit number into a little-endian 16-byte array. // Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes. dataUnitNo = startDataUnitNo->Value; *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); *((unsigned __int64 *) byteBufUnitNo + 1) = 0; if (length % BYTES_PER_XTS_BLOCK) TC_THROW_FATAL_EXCEPTION; blockCount = length / BYTES_PER_XTS_BLOCK; // Process all blocks in the buffer while (blockCount > 0) { if (blockCount < BLOCKS_PER_XTS_DATA_UNIT) endBlock = startBlock + (unsigned int) blockCount; else endBlock = BLOCKS_PER_XTS_DATA_UNIT; whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; // Encrypt the data unit number using the secondary key (in order to generate the first // whitening value for this data unit) *whiteningValuePtr64 = *((unsigned __int64 *) byteBufUnitNo); *(whiteningValuePtr64 + 1) = 0; EncipherBlock (cipher, whiteningValue, ks2); // Generate subsequent whitening values for blocks in this data unit. Note that all generated 128-bit // whitening values are stored in memory as a sequence of 64-bit integers in reverse order. for (block = 0; block < endBlock; block++) { if (block >= startBlock) { *whiteningValuesPtr64-- = *whiteningValuePtr64++; *whiteningValuesPtr64-- = *whiteningValuePtr64; } else whiteningValuePtr64++; // Derive the next whitening value #if BYTE_ORDER == LITTLE_ENDIAN // Little-endian platforms finalCarry = (*whiteningValuePtr64 & 0x8000000000000000) ? 135 : 0; *whiteningValuePtr64-- <<= 1; if (*whiteningValuePtr64 & 0x8000000000000000) *(whiteningValuePtr64 + 1) |= 1; *whiteningValuePtr64 <<= 1; #else // Big-endian platforms finalCarry = (*whiteningValuePtr64 & 0x80) ? 135 : 0; *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); whiteningValuePtr64--; if (*whiteningValuePtr64 & 0x80) *(whiteningValuePtr64 + 1) |= 0x0100000000000000; *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); #endif whiteningValue[0] ^= finalCarry; } dataUnitBufPtr = bufPtr; whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; // Encrypt all blocks in this data unit for (block = startBlock; block < endBlock; block++) { // Pre-whitening *bufPtr++ ^= *whiteningValuesPtr64--; *bufPtr++ ^= *whiteningValuesPtr64--; } // Actual encryption EncipherBlocks (cipher, dataUnitBufPtr, ks, endBlock - startBlock); bufPtr = dataUnitBufPtr; whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; for (block = startBlock; block < endBlock; block++) { // Post-whitening *bufPtr++ ^= *whiteningValuesPtr64--; *bufPtr++ ^= *whiteningValuesPtr64--; } blockCount -= endBlock - startBlock; startBlock = 0; dataUnitNo++; *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); } FAST_ERASE64 (whiteningValue, sizeof (whiteningValue)); FAST_ERASE64 (whiteningValues, sizeof (whiteningValues)); }
// Optimized for encryption algorithms not supporting intra-data-unit parallelization static void DecryptBufferXTSNonParallel (unsigned __int8 *buffer, TC_LARGEST_COMPILER_UINT length, const UINT64_STRUCT *startDataUnitNo, unsigned int startCipherBlockNo, unsigned __int8 *ks, unsigned __int8 *ks2, int cipher) { unsigned __int8 finalCarry; unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK]; unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK]; unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; unsigned __int64 *bufPtr = (unsigned __int64 *) buffer; unsigned int startBlock = startCipherBlockNo, endBlock, block; TC_LARGEST_COMPILER_UINT blockCount, dataUnitNo; // Convert the 64-bit data unit number into a little-endian 16-byte array. // Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes. dataUnitNo = startDataUnitNo->Value; *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); *((unsigned __int64 *) byteBufUnitNo + 1) = 0; if (length % BYTES_PER_XTS_BLOCK) TC_THROW_FATAL_EXCEPTION; blockCount = length / BYTES_PER_XTS_BLOCK; // Process all blocks in the buffer while (blockCount > 0) { if (blockCount < BLOCKS_PER_XTS_DATA_UNIT) endBlock = startBlock + (unsigned int) blockCount; else endBlock = BLOCKS_PER_XTS_DATA_UNIT; whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; // Encrypt the data unit number using the secondary key (in order to generate the first // whitening value for this data unit) *whiteningValuePtr64 = *((unsigned __int64 *) byteBufUnitNo); *(whiteningValuePtr64 + 1) = 0; EncipherBlock (cipher, whiteningValue, ks2); // Generate (and apply) subsequent whitening values for blocks in this data unit and // decrypt all relevant blocks in this data unit for (block = 0; block < endBlock; block++) { if (block >= startBlock) { // Post-whitening *bufPtr++ ^= *whiteningValuePtr64++; *bufPtr-- ^= *whiteningValuePtr64--; // Actual decryption DecipherBlock (cipher, bufPtr, ks); // Pre-whitening *bufPtr++ ^= *whiteningValuePtr64++; *bufPtr++ ^= *whiteningValuePtr64; } else whiteningValuePtr64++; // Derive the next whitening value #if BYTE_ORDER == LITTLE_ENDIAN // Little-endian platforms finalCarry = (*whiteningValuePtr64 & 0x8000000000000000) ? 135 : 0; *whiteningValuePtr64-- <<= 1; if (*whiteningValuePtr64 & 0x8000000000000000) *(whiteningValuePtr64 + 1) |= 1; *whiteningValuePtr64 <<= 1; #else // Big-endian platforms finalCarry = (*whiteningValuePtr64 & 0x80) ? 135 : 0; *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); whiteningValuePtr64--; if (*whiteningValuePtr64 & 0x80) *(whiteningValuePtr64 + 1) |= 0x0100000000000000; *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); #endif whiteningValue[0] ^= finalCarry; } blockCount -= endBlock - startBlock; startBlock = 0; dataUnitNo++; *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); } FAST_ERASE64 (whiteningValue, sizeof (whiteningValue)); }
// Optimized for encryption algorithms supporting intra-data-unit parallelization static void DecryptBufferXTSParallel (unsigned __int8 *buffer, TC_LARGEST_COMPILER_UINT length, const UINT64_STRUCT *startDataUnitNo, unsigned int startCipherBlockNo, unsigned __int8 *ks, unsigned __int8 *ks2, int cipher) { unsigned __int8 finalCarry; unsigned __int8 whiteningValues [ENCRYPTION_DATA_UNIT_SIZE]; unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK]; unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK]; unsigned __int64 *whiteningValuesPtr64 = (unsigned __int64 *) whiteningValues; unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; unsigned __int64 *bufPtr = (unsigned __int64 *) buffer; unsigned __int64 *dataUnitBufPtr; unsigned int startBlock = startCipherBlockNo, endBlock, block; unsigned __int64 *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1; TC_LARGEST_COMPILER_UINT blockCount, dataUnitNo; // Convert the 64-bit data unit number into a little-endian 16-byte array. // Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes. dataUnitNo = startDataUnitNo->Value; *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); *((unsigned __int64 *) byteBufUnitNo + 1) = 0; if (length % BYTES_PER_XTS_BLOCK) TC_THROW_FATAL_EXCEPTION; blockCount = length / BYTES_PER_XTS_BLOCK; // Process all blocks in the buffer while (blockCount > 0) { if (blockCount < BLOCKS_PER_XTS_DATA_UNIT) endBlock = startBlock + (unsigned int) blockCount; else endBlock = BLOCKS_PER_XTS_DATA_UNIT; whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; // Encrypt the data unit number using the secondary key (in order to generate the first // whitening value for this data unit) *whiteningValuePtr64 = *((unsigned __int64 *) byteBufUnitNo); *(whiteningValuePtr64 + 1) = 0; EncipherBlock (cipher, whiteningValue, ks2); // Generate subsequent whitening values for blocks in this data unit. Note that all generated 128-bit // whitening values are stored in memory as a sequence of 64-bit integers in reverse order. for (block = 0; block < endBlock; block++) { if (block >= startBlock) { *whiteningValuesPtr64-- = *whiteningValuePtr64++; *whiteningValuesPtr64-- = *whiteningValuePtr64; } else whiteningValuePtr64++; // Derive the next whitening value #if BYTE_ORDER == LITTLE_ENDIAN // Little-endian platforms finalCarry = (*whiteningValuePtr64 & 0x8000000000000000) ? 135 : 0; *whiteningValuePtr64-- <<= 1; if (*whiteningValuePtr64 & 0x8000000000000000) *(whiteningValuePtr64 + 1) |= 1; *whiteningValuePtr64 <<= 1; #else // Big-endian platforms finalCarry = (*whiteningValuePtr64 & 0x80) ? 135 : 0; *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); whiteningValuePtr64--; if (*whiteningValuePtr64 & 0x80) *(whiteningValuePtr64 + 1) |= 0x0100000000000000; *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); #endif whiteningValue[0] ^= finalCarry; } dataUnitBufPtr = bufPtr; whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; // Decrypt blocks in this data unit for (block = startBlock; block < endBlock; block++) { *bufPtr++ ^= *whiteningValuesPtr64--; *bufPtr++ ^= *whiteningValuesPtr64--; } DecipherBlocks (cipher, dataUnitBufPtr, ks, endBlock - startBlock); bufPtr = dataUnitBufPtr; whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; for (block = startBlock; block < endBlock; block++) { *bufPtr++ ^= *whiteningValuesPtr64--; *bufPtr++ ^= *whiteningValuesPtr64--; } blockCount -= endBlock - startBlock; startBlock = 0; dataUnitNo++; *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); } FAST_ERASE64 (whiteningValue, sizeof (whiteningValue)); FAST_ERASE64 (whiteningValues, sizeof (whiteningValues)); }
/* * Sends a KMS request via RPC and receives a response. * Parameters are raw (encrypted) reqeuests / responses. * Returns 0 on success. */ RpcStatus rpcSendRequest(const RpcCtx sock, const BYTE *const kmsRequest, const size_t requestSize, BYTE **kmsResponse, size_t *const responseSize) { #define MAX_EXCESS_BYTES 16 RPC_HEADER *RequestHeader, ResponseHeader; RPC_REQUEST64 *RpcRequest; RPC_RESPONSE64 _Response; int status; int_fast8_t useNdr64 = RpcFlags.HasNDR64 && UseClientRpcNDR64 && firstPacketSent; size_t size = sizeof(RPC_HEADER) + (useNdr64 ? sizeof(RPC_REQUEST64) : sizeof(RPC_REQUEST)) + requestSize; size_t responseSize2; *kmsResponse = NULL; BYTE *_Request = (BYTE*)vlmcsd_malloc(size); RequestHeader = (RPC_HEADER*)_Request; RpcRequest = (RPC_REQUEST64*)(_Request + sizeof(RPC_HEADER)); createRpcHeader(RequestHeader, RPC_PT_REQUEST, (WORD)size); // Increment CallId for next Request CallId++; RpcRequest->Opnum = 0; if (useNdr64) { RpcRequest->ContextId = LE16(1); // We negotiate NDR64 always as context 1 RpcRequest->AllocHint = LE32((DWORD)(requestSize + sizeof(RpcRequest->Ndr64))); RpcRequest->Ndr64.DataLength = LE64((uint64_t)requestSize); RpcRequest->Ndr64.DataSizeIs = LE64((uint64_t)requestSize); memcpy(RpcRequest->Ndr64.Data, kmsRequest, requestSize); } else { RpcRequest->ContextId = 0; // We negotiate NDR32 always as context 0 RpcRequest->AllocHint = LE32((DWORD)(requestSize + sizeof(RpcRequest->Ndr))); RpcRequest->Ndr.DataLength = LE32((DWORD)requestSize); RpcRequest->Ndr.DataSizeIs = LE32((DWORD)requestSize); memcpy(RpcRequest->Ndr.Data, kmsRequest, requestSize); } for (;;) { int bytesread; if (!_send(sock, _Request, (int)size)) { printerrorf("\nFatal: Could not send RPC request\n"); status = RPC_S_COMM_FAILURE; break; } if (!_recv(sock, &ResponseHeader, sizeof(RPC_HEADER))) { printerrorf("\nFatal: No RPC response received from server\n"); status = RPC_S_COMM_FAILURE; break; } if ((status = checkRpcResponseHeader(&ResponseHeader, RequestHeader, RPC_PT_RESPONSE, &printerrorf))) break; size = useNdr64 ? sizeof(RPC_RESPONSE64) : sizeof(RPC_RESPONSE); if (size > LE16(ResponseHeader.FragLength) - sizeof(ResponseHeader)) size = LE16(ResponseHeader.FragLength) - sizeof(ResponseHeader); if (!_recv(sock, &_Response, (int)size)) { printerrorf("\nFatal: RPC response is incomplete\n"); status = RPC_S_COMM_FAILURE; break; } if (_Response.CancelCount != 0) { printerrorf("\nFatal: RPC response cancel count is not 0\n"); status = RPC_S_CALL_CANCELLED; break; } if (_Response.ContextId != (useNdr64 ? LE16(1) : 0)) { printerrorf("\nFatal: RPC response context id %u is not bound\n", (unsigned int)LE16(_Response.ContextId)); status = RPC_X_SS_CONTEXT_DAMAGED; break; } int_fast8_t sizesMatch; if (useNdr64) { *responseSize = (size_t)LE64(_Response.Ndr64.DataLength); responseSize2 = (size_t)LE64(_Response.Ndr64.DataSizeIs); if (/*!*responseSize ||*/ !_Response.Ndr64.DataSizeMax) { status = (int)LE32(_Response.Ndr64.status); break; } sizesMatch = (size_t)LE64(_Response.Ndr64.DataLength) == responseSize2; } else { *responseSize = (size_t)LE32(_Response.Ndr.DataLength); responseSize2 = (size_t)LE32(_Response.Ndr.DataSizeIs); if (/*!*responseSize ||*/ !_Response.Ndr.DataSizeMax) { status = (int)LE32(_Response.Ndr.status); break; } sizesMatch = (size_t)LE32(_Response.Ndr.DataLength) == responseSize2; } if (!sizesMatch) { printerrorf("\nFatal: NDR data length (%u) does not match NDR data size (%u)\n", (uint32_t)*responseSize, (uint32_t)LE32(_Response.Ndr.DataSizeIs) ); status = RPC_S_PROTOCOL_ERROR; break; } *kmsResponse = (BYTE*)vlmcsd_malloc(*responseSize + MAX_EXCESS_BYTES); // If RPC stub is too short, assume missing bytes are zero (same ill behavior as MS RPC) memset(*kmsResponse, 0, *responseSize + MAX_EXCESS_BYTES); // Read up to 16 bytes more than bytes expected to detect faulty KMS emulators if ((bytesread = recv(sock, (char*)*kmsResponse, (int)(*responseSize) + MAX_EXCESS_BYTES, 0)) < (int)*responseSize) { printerrorf("\nFatal: No or incomplete KMS response received. Required %u bytes but only got %i\n", (uint32_t)*responseSize, (int32_t)(bytesread < 0 ? 0 : bytesread) ); status = RPC_S_PROTOCOL_ERROR; break; } DWORD *pReturnCode; size_t len = *responseSize + (useNdr64 ? sizeof(_Response.Ndr64) : sizeof(_Response.Ndr)) + sizeof(*pReturnCode); size_t pad = ((~len & 3) + 1) & 3; if (len + pad != LE32(_Response.AllocHint)) { printerrorf("\nWarning: RPC stub size is %u, should be %u (probably incorrect padding)\n", (uint32_t)LE32(_Response.AllocHint), (uint32_t)(len + pad)); } else { size_t i; for (i = 0; i < pad; i++) { if (*(*kmsResponse + *responseSize + sizeof(*pReturnCode) + i)) { printerrorf("\nWarning: RPC stub data not padded to zeros according to Microsoft standard\n"); break; } } } pReturnCode = (DWORD*)(*kmsResponse + *responseSize + pad); status = LE32(UA32(pReturnCode)); break; } free(_Request); firstPacketSent = TRUE; return status; #undef MAX_EXCESS_BYTES }
static void CheckRpcRequest(const RPC_REQUEST64 *const Request, const unsigned int len, WORD* NdrCtx, WORD* Ndr64Ctx, WORD Ctx) { uint_fast8_t kmsMajorVersion; uint32_t requestSize = Ctx != *Ndr64Ctx ? sizeof(RPC_REQUEST) : sizeof(RPC_REQUEST64); if (len < requestSize) { logger("Fatal: RPC request (including header) must be at least %i bytes but is only %i bytes.\n", (int)(sizeof(RPC_HEADER) + requestSize), (int)(len + sizeof(RPC_HEADER)) ); return; } if (len < requestSize + sizeof(DWORD)) { logger("Fatal: KMS Request too small to contain version info (less than 4 bytes).\n"); return; } if (Ctx != *Ndr64Ctx) kmsMajorVersion = (uint_fast8_t)LE16(((WORD*)Request->Ndr.Data)[1]); else kmsMajorVersion = (uint_fast8_t)LE16(((WORD*)Request->Ndr64.Data)[1]); if (kmsMajorVersion > 6) { logger("Fatal: KMSv%u is not supported.\n", (unsigned int)kmsMajorVersion); } else { if (len > _Versions[kmsMajorVersion - 4].RequestSize + requestSize) logger("Warning: %u excess bytes in RPC request.\n", len - (_Versions[kmsMajorVersion - 4].RequestSize + requestSize) ); } if (Ctx != *Ndr64Ctx && Ctx != *NdrCtx) { if (*Ndr64Ctx == RPC_INVALID_CTX) { logger("Warning: Context id should be %u but is %u.\n", (unsigned int)*NdrCtx, Ctx); } else { logger("Warning: Context id should be %u (NDR32) or %u (NDR64) but is %u.\n", (unsigned int)*NdrCtx, (unsigned int)*Ndr64Ctx, Ctx ); } } if (Request->Opnum) logger("Warning: OpNum should be 0 but is %u.\n", (unsigned int)LE16(Request->Opnum) ); if (LE32(Request->AllocHint) != len - sizeof(RPC_REQUEST) + sizeof(Request->Ndr)) logger("Warning: Allocation hint should be %u but is %u.\n", len + sizeof(Request->Ndr), LE32(Request->AllocHint) ); if (Ctx != *Ndr64Ctx) { if (LE32(Request->Ndr.DataLength) != len - sizeof(RPC_REQUEST)) logger("Warning: NDR32 data length field should be %u but is %u.\n", len - sizeof(RPC_REQUEST), LE32(Request->Ndr.DataLength) ); if (LE32(Request->Ndr.DataSizeIs) != len - sizeof(RPC_REQUEST)) logger("Warning: NDR32 data size field should be %u but is %u.\n", len - sizeof(RPC_REQUEST), LE32(Request->Ndr.DataSizeIs) ); } else { if (LE64(Request->Ndr64.DataLength) != len - sizeof(RPC_REQUEST64)) logger("Warning: NDR32 data length field should be %u but is %u.\n", len - sizeof(RPC_REQUEST) + sizeof(Request->Ndr), LE64(Request->Ndr64.DataLength) ); if (LE64(Request->Ndr64.DataSizeIs) != len - sizeof(RPC_REQUEST64)) logger("Warning: NDR32 data size field should be %u but is %u.\n", len - sizeof(RPC_REQUEST64), LE64(Request->Ndr64.DataSizeIs) ); } }
/* * Handles the actual KMS request from the client. * Calls KMS functions (CreateResponseV4 or CreateResponseV6) in kms.c * Returns size of the KMS response packet or 0 on failure. * * The RPC packet size (excluding header) is actually in Response->AllocHint */ static int rpcRequest(const RPC_REQUEST64 *const Request, RPC_RESPONSE64 *const Response, const DWORD RpcAssocGroup_unused, const SOCKET sock_unused, WORD* NdrCtx, WORD* Ndr64Ctx, BYTE isValid, const char* const ipstr) { int ResponseSize; // <0 = Errorcode (HRESULT) BYTE* requestData; BYTE* responseData; BYTE* pRpcReturnCode; int len; # ifndef SIMPLE_RPC WORD Ctx = LE16(Request->ContextId); if (Ctx == *NdrCtx) { requestData = (BYTE*)&Request->Ndr.Data; responseData = (BYTE*)&Response->Ndr.Data; } else if (Ctx == *Ndr64Ctx) { requestData = (BYTE*)&Request->Ndr64.Data; responseData = (BYTE*)&Response->Ndr64.Data; } else { return SendError(Response, RPC_NCA_UNK_IF); } # else // SIMPLE_RPC requestData = (BYTE*)&Request->Ndr.Data; responseData = (BYTE*)&Response->Ndr.Data; # endif // SIMPLE_RPC ResponseSize = 0x8007000D; // Invalid Data if (isValid) { uint16_t majorIndex = LE16(((WORD*)requestData)[1]) - 4; if (!((ResponseSize = _Versions[majorIndex].CreateResponse(requestData, responseData, ipstr)))) ResponseSize = 0x8007000D; } # ifndef SIMPLE_RPC if (Ctx != *Ndr64Ctx) { # endif // !SIMPLE_RPC if (ResponseSize < 0) { Response->Ndr.DataSizeMax = Response->Ndr.DataLength = 0; len = sizeof(Response->Ndr) - sizeof(Response->Ndr.DataSizeIs); } else { Response->Ndr.DataSizeMax = LE32(0x00020000); Response->Ndr.DataLength = Response->Ndr.DataSizeIs = LE32(ResponseSize); len = ResponseSize + sizeof(Response->Ndr); } # ifndef SIMPLE_RPC } else { if (ResponseSize < 0) { Response->Ndr64.DataSizeMax = Response->Ndr64.DataLength = 0; len = sizeof(Response->Ndr64) - sizeof(Response->Ndr64.DataSizeIs); } else { Response->Ndr64.DataSizeMax = LE64(0x00020000ULL); Response->Ndr64.DataLength = Response->Ndr64.DataSizeIs = LE64((uint64_t)ResponseSize); len = ResponseSize + sizeof(Response->Ndr64); } } # endif // !SIMPLE_RPC pRpcReturnCode = ((BYTE*)&Response->Ndr) + len; UA32(pRpcReturnCode) = ResponseSize < 0 ? LE32(ResponseSize) : 0; len += sizeof(DWORD); // Pad zeros to 32-bit align (seems not neccassary but Windows RPC does it this way) int pad = ((~len & 3) + 1) & 3; memset(pRpcReturnCode + sizeof(DWORD), 0, pad); len += pad; Response->AllocHint = LE32(len); Response->ContextId = Request->ContextId; *((WORD*)&Response->CancelCount) = 0; // CancelCount + Pad1 return len + 8; }
static void EncryptBufferXTS8Byte(unsigned __int8 *buffer, GST_LARGEST_COMPILER_UINT length, const UINT64_STRUCT *startDataUnitNo, unsigned int startCipherBlockNo, unsigned __int8 *ks, unsigned __int8 *ks2, int cipher) { unsigned __int8 finalCarry; unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK_SMALL]; unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK_SMALL]; unsigned __int32 *whiteningValuePtr32 = (unsigned __int32 *)whiteningValue; unsigned __int32 *bufPtr = (unsigned __int32 *)buffer; unsigned __int32 startBlock = startCipherBlockNo, endBlock, block; GST_LARGEST_COMPILER_UINT blockCount, dataUnitNo; unsigned __int8 xor_ks[MAX_EXPANDED_KEY]; dataUnitNo = startDataUnitNo->Value; *((unsigned __int64 *) byteBufUnitNo) = (unsigned __int64) LE64(dataUnitNo); if (length % BYTES_PER_XTS_BLOCK_SMALL) GST_THROW_FATAL_EXCEPTION; blockCount = length / BYTES_PER_XTS_BLOCK_SMALL; memcpy(xor_ks, ks, CipherGetKeyScheduleSize(cipher)); while (blockCount > 0) { if (blockCount < BLOCKS_PER_XTS_DATA_UNIT_SMALL) endBlock = startBlock + (unsigned __int32) blockCount; else endBlock = BLOCKS_PER_XTS_DATA_UNIT_SMALL; whiteningValuePtr32 = (unsigned __int32 *) whiteningValue; //Generate first whitening value *whiteningValuePtr32 = *((unsigned __int32 *) byteBufUnitNo); *(whiteningValuePtr32+1) = *((unsigned __int32 *) byteBufUnitNo+1); EncipherBlock (cipher, whiteningValue, ks2); //XOR ks with the current DataUnitNo XorKeySchedule(cipher, ks, xor_ks, byteBufUnitNo, 8); //Generate subsequent whitening values for blocks for (block = 0; block < endBlock; block++) { if (block >= startBlock) { //Pre-whitening *bufPtr++ ^= *whiteningValuePtr32++; *bufPtr-- ^= *whiteningValuePtr32--; //Actual encryption EncipherBlock(cipher, bufPtr, xor_ks); //Post-whitening *bufPtr++ ^= *whiteningValuePtr32++; *bufPtr++ ^= *whiteningValuePtr32; } else whiteningValuePtr32++; //Derive the next whitening value #if BYTE_ORDER == LITTLE_ENDIAN //Little-endian platforms finalCarry = (*whiteningValuePtr32 & 0x80000000) ? 135 : 0; *whiteningValuePtr32-- <<= 1; if (*whiteningValuePtr32 & 0x80000000) *(whiteningValuePtr32 + 1) |= 1; *whiteningValuePtr32 <<= 1; #else //Big-endian platforms finalCarry = (*whiteningValuePtr32 & 0x80) ? 135 : 0; *whiteningValuePtr32 = LE32 (LE32 (*whiteningValuePtr32) << 1); whiteningValuePtr32--; if (*whiteningValuePtr32 & 0x80) *(whiteningValuePtr32 + 1) |= 0x01000000; *whiteningValuePtr32 = LE32 (LE32 (*whiteningValuePtr32) << 1); #endif whiteningValue[0] ^= finalCarry; } blockCount -= endBlock - startBlock; startBlock = 0; dataUnitNo++; *((unsigned __int64 *) byteBufUnitNo) = (unsigned __int64) LE64 (dataUnitNo); } FAST_ERASE32(whiteningValue, sizeof(whiteningValue)); }
int salsa20_init(salsa20_ctx_t *ctx, uchar_t *salt, int saltlen, uchar_t *pwd, int pwd_len, uchar_t *nonce, int enc) { struct timespec tp; uint64_t tv; uchar_t num[25]; uchar_t IV[32]; uchar_t *key = ctx->pkey; #ifndef _USE_PBK int logN; uint32_t r, p; uint64_t N; if (XSALSA20_CRYPTO_NONCEBYTES % 8) { log_msg(LOG_ERR, 0, "XSALSA20_CRYPTO_NONCEBYTES is not a multiple of 8!\n"); return (-1); } pickparams(&logN, &r, &p); N = (uint64_t)(1) << logN; if (crypto_scrypt(pwd, pwd_len, salt, saltlen, N, r, p, key, ctx->keylen)) { log_msg(LOG_ERR, 0, "Scrypt failed\n"); return (-1); } #else rv = PKCS5_PBKDF2_HMAC(pwd, pwd_len, salt, saltlen, PBE_ROUNDS, EVP_sha256(), ctx->keylen, key); if (rv != ctx->keylen) { log_msg(LOG_ERR, 0, "Key size is %d bytes - should be %d bits\n", i, ctx->keylen); return (-1); } #endif /* * Copy the key. XSalsa20 core cipher always uses a 256-bit key. If we are using a * 128-bit key then the key value is repeated twice to form a 256-bit value. * This approach is based on the Salsa20 code submitted to eSTREAM. See the function * ECRYPT_keysetup() in the Salsa20 submission: * http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/salsa20/full/ref/salsa20.c?rev=161&view=auto * * The input values corresponding to a 256-bit key contain repeated values if key * length is 128-bit. */ memcpy(ctx->key, key, ctx->keylen); if (ctx->keylen < XSALSA20_CRYPTO_KEYBYTES) { uchar_t *k; k = ctx->key + ctx->keylen; memcpy(k, key, XSALSA20_CRYPTO_KEYBYTES - ctx->keylen); } if (enc) { int i; uint64_t *n, *n1; // Derive 192-bit nonce if (RAND_status() != 1 || RAND_bytes(IV, XSALSA20_CRYPTO_NONCEBYTES) != 1) { if (geturandom_bytes(IV, XSALSA20_CRYPTO_NONCEBYTES) != 0) { if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1) { time((time_t *)&tv); } else { tv = tp.tv_sec * 1000UL + tp.tv_nsec; } sprintf((char *)num, "%" PRIu64, tv); PKCS5_PBKDF2_HMAC((const char *)num, strlen((char *)num), salt, saltlen, PBE_ROUNDS, EVP_sha256(), 32, IV); } } n = (uint64_t *)IV; n1 = (uint64_t *)(ctx->nonce); for (i = 0; i < XSALSA20_CRYPTO_NONCEBYTES/8; i++) { *n1 = LE64(*n); n++; n1++; } // Nullify stack components memset(num, 0, 25); memset(IV, 0, 32); memset(&tp, 0, sizeof (tp)); tv = 0; } else { memcpy(ctx->nonce, nonce, XSALSA20_CRYPTO_NONCEBYTES); memset(nonce, 0, XSALSA20_CRYPTO_NONCEBYTES); } return (0); }