static char * digest_end(DIGEST_CTX *c, char *buf) { switch (digesttype) { case DIGEST_MD5: return (MD5End(&(c->MD5), buf)); case DIGEST_RIPEMD160: return (RIPEMD160_End(&(c->RIPEMD160), buf)); case DIGEST_SHA1: return (SHA1_End(&(c->SHA1), buf)); case DIGEST_SHA256: return (SHA256_End(&(c->SHA256), buf)); case DIGEST_SHA512: return (SHA512_End(&(c->SHA512), buf)); default: return (NULL); } }
char * SHA256_File(char *filename, char *buf) { unsigned char buffer[BUFSIZ * 20]; SHA256_CTX ctx; int fd, num, oerrno; _DIAGASSERT(filename != NULL); /* XXX: buf may be NULL ? */ SHA256_Init(&ctx); if ((fd = open(filename, O_RDONLY)) < 0) return (0); while ((num = read(fd, buffer, sizeof(buffer))) > 0) SHA256_Update(&ctx, buffer, (size_t) num); oerrno = errno; close(fd); errno = oerrno; return (num < 0 ? 0 : SHA256_End(&ctx, buf)); }
/* * This function expands the internal state of the prng to fulfill any number * of bytes we need for this request. We only use this call if we need more * than can be supplied by a single call to SHA256_HashBuf. * * This function is specified in NIST SP 800-90 section 10.1.1.4, Hashgen */ static void prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes, unsigned int no_of_returned_bytes) { PRUint8 data[VSize(rng)]; PRUint8 thisHash[SHA256_LENGTH]; PRUint8 *lastHash = rng->lastOutput; PORT_Memcpy(data, V(rng), VSize(rng)); while (no_of_returned_bytes) { SHA256Context ctx; unsigned int len; unsigned int carry; SHA256_Begin(&ctx); SHA256_Update(&ctx, data, sizeof data); SHA256_End(&ctx, thisHash, &len, SHA256_LENGTH); if (PORT_Memcmp(lastHash, thisHash, len) == 0) { rng->isValid = PR_FALSE; break; } if (no_of_returned_bytes < SHA256_LENGTH) { len = no_of_returned_bytes; } PORT_Memcpy(returned_bytes, thisHash, len); lastHash = returned_bytes; returned_bytes += len; no_of_returned_bytes -= len; /* The carry parameter is a bool (increment or not). * This increments data if no_of_returned_bytes is not zero */ carry = no_of_returned_bytes; PRNG_ADD_CARRY_ONLY(data, (sizeof data)- 1, carry); } PORT_Memcpy(rng->lastOutput, thisHash, SHA256_LENGTH); PORT_Memset(data, 0, sizeof data); PORT_Memset(thisHash, 0, sizeof thisHash); }
/* * This function expands the internal state of the prng to fulfill any number * of bytes we need for this request. We only use this call if we need more * than can be supplied by a single call to SHA256_HashBuf. * * This function is specified in NIST SP 800-90 section 10.1.1.4, Hashgen */ static void prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes, unsigned int no_of_returned_bytes) { PRUint8 data[VSize(rng)]; PORT_Memcpy(data, V(rng), VSize(rng)); while (no_of_returned_bytes) { SHA256Context ctx; unsigned int len; unsigned int carry; int k1; SHA256_Begin(&ctx); SHA256_Update(&ctx, data, sizeof data); SHA256_End(&ctx, returned_bytes, &len, no_of_returned_bytes); returned_bytes += len; no_of_returned_bytes -= len; /* The carry parameter is a bool (increment or not). * This increments data if no_of_returned_bytes is not zero */ PRNG_ADD_CARRY_ONLY(data, (sizeof data)- 1, no_of_returned_bytes); } PORT_Memset(data, 0, sizeof data); }
bool GMPLoaderImpl::Load(const char* aLibPath, uint32_t aLibPathLen, char* aOriginSalt, uint32_t aOriginSaltLen, const GMPPlatformAPI* aPlatformAPI) { std::string nodeId; #ifdef HASH_NODE_ID_WITH_DEVICE_ID if (aOriginSaltLen > 0) { string16 deviceId; int volumeId; if (!rlz_lib::GetRawMachineId(&deviceId, &volumeId)) { return false; } SHA256Context ctx; SHA256_Begin(&ctx); SHA256_Update(&ctx, (const uint8_t*)aOriginSalt, aOriginSaltLen); SHA256_Update(&ctx, (const uint8_t*)deviceId.c_str(), deviceId.size() * sizeof(string16::value_type)); SHA256_Update(&ctx, (const uint8_t*)&volumeId, sizeof(int)); uint8_t digest[SHA256_LENGTH] = {0}; unsigned int digestLen = 0; SHA256_End(&ctx, digest, &digestLen, SHA256_LENGTH); // Overwrite all data involved in calculation as it could potentially // identify the user, so there's no chance a GMP can read it and use // it for identity tracking. memset(&ctx, 0, sizeof(ctx)); memset(aOriginSalt, 0, aOriginSaltLen); volumeId = 0; memset(&deviceId[0], '*', sizeof(string16::value_type) * deviceId.size()); deviceId = L""; if (!rlz_lib::BytesToString(digest, SHA256_LENGTH, &nodeId)) { return false; } // We've successfully bound the origin salt to node id. // rlz_lib::GetRawMachineId and/or the system functions it // called could have left user identifiable data on the stack, // so carefully zero the stack down to the guard page. uint8_t* top; uint8_t* bottom; if (!GetStackAfterCurrentFrame(&top, &bottom)) { return false; } assert(top >= bottom); // Inline instructions equivalent to RtlSecureZeroMemory(). // We can't just use RtlSecureZeroMemory here directly, as in debug // builds, RtlSecureZeroMemory() can't be inlined, and the stack // memory it uses would get wiped by itself running, causing crashes. for (volatile uint8_t* p = (volatile uint8_t*)bottom; p < top; p++) { *p = 0; } } else #endif { nodeId = std::string(aOriginSalt, aOriginSalt + aOriginSaltLen); } // Start the sandbox now that we've generated the device bound node id. // This must happen after the node id is bound to the device id, as // generating the device id requires privileges. if (mSandboxStarter) { mSandboxStarter->Start(aLibPath); } // Load the GMP. PRLibSpec libSpec; libSpec.value.pathname = aLibPath; libSpec.type = PR_LibSpec_Pathname; mLib = PR_LoadLibraryWithFlags(libSpec, 0); if (!mLib) { return false; } GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit")); if (!initFunc) { return false; } if (initFunc(aPlatformAPI) != GMPNoErr) { return false; } GMPSetNodeIdFunc setNodeIdFunc = reinterpret_cast<GMPSetNodeIdFunc>(PR_FindFunctionSymbol(mLib, "GMPSetNodeId")); if (setNodeIdFunc) { setNodeIdFunc(nodeId.c_str(), nodeId.size()); } mGetAPIFunc = reinterpret_cast<GMPGetAPIFunc>(PR_FindFunctionSymbol(mLib, "GMPGetAPI")); if (!mGetAPIFunc) { return false; } return true; }
bool GMPLoaderImpl::Load(const char* aLibPath, uint32_t aLibPathLen, char* aOriginSalt, uint32_t aOriginSaltLen, const GMPPlatformAPI* aPlatformAPI) { std::string nodeId; #ifdef HASH_NODE_ID_WITH_DEVICE_ID if (aOriginSaltLen > 0) { string16 deviceId; int volumeId; if (!rlz_lib::GetRawMachineId(&deviceId, &volumeId)) { return false; } SHA256Context ctx; SHA256_Begin(&ctx); SHA256_Update(&ctx, (const uint8_t*)aOriginSalt, aOriginSaltLen); SHA256_Update(&ctx, (const uint8_t*)deviceId.c_str(), deviceId.size() * sizeof(string16::value_type)); SHA256_Update(&ctx, (const uint8_t*)&volumeId, sizeof(int)); uint8_t digest[SHA256_LENGTH] = {0}; unsigned int digestLen = 0; SHA256_End(&ctx, digest, &digestLen, SHA256_LENGTH); // Overwrite all data involved in calculation as it could potentially // identify the user, so there's no chance a GMP can read it and use // it for identity tracking. memset(&ctx, 0, sizeof(ctx)); memset(aOriginSalt, 0, aOriginSaltLen); volumeId = 0; memset(&deviceId[0], '*', sizeof(string16::value_type) * deviceId.size()); deviceId = L""; if (!rlz_lib::BytesToString(digest, SHA256_LENGTH, &nodeId)) { return false; } // We've successfully bound the origin salt to node id. // rlz_lib::GetRawMachineId and/or the system functions it // called could have left user identifiable data on the stack, // so carefully zero the stack down to the guard page. uint8_t* top; uint8_t* bottom; if (!GetStackAfterCurrentFrame(&top, &bottom)) { return false; } assert(top >= bottom); // Inline instructions equivalent to RtlSecureZeroMemory(). // We can't just use RtlSecureZeroMemory here directly, as in debug // builds, RtlSecureZeroMemory() can't be inlined, and the stack // memory it uses would get wiped by itself running, causing crashes. for (volatile uint8_t* p = (volatile uint8_t*)bottom; p < top; p++) { *p = 0; } } else #endif { nodeId = std::string(aOriginSalt, aOriginSalt + aOriginSaltLen); } #if defined(XP_WIN) && defined(MOZ_SANDBOX) // If the GMP DLL is a side-by-side assembly with static imports then the DLL // loader will attempt to create an activation context which will fail because // of the sandbox. If we create an activation context before we start the // sandbox then this one will get picked up by the DLL loader. int pathLen = MultiByteToWideChar(CP_ACP, 0, aLibPath, -1, nullptr, 0); if (pathLen == 0) { return false; } wchar_t* widePath = new wchar_t[pathLen]; if (MultiByteToWideChar(CP_ACP, 0, aLibPath, -1, widePath, pathLen) == 0) { delete[] widePath; return false; } ACTCTX actCtx = { sizeof(actCtx) }; actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; actCtx.lpSource = widePath; actCtx.lpResourceName = ISOLATIONAWARE_MANIFEST_RESOURCE_ID; ScopedActCtxHandle actCtxHandle(CreateActCtx(&actCtx)); delete[] widePath; #endif // Start the sandbox now that we've generated the device bound node id. // This must happen after the node id is bound to the device id, as // generating the device id requires privileges. if (mSandboxStarter) { mSandboxStarter->Start(aLibPath); } // Load the GMP. PRLibSpec libSpec; libSpec.value.pathname = aLibPath; libSpec.type = PR_LibSpec_Pathname; mLib = PR_LoadLibraryWithFlags(libSpec, 0); if (!mLib) { return false; } GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit")); if (!initFunc) { return false; } if (initFunc(aPlatformAPI) != GMPNoErr) { return false; } GMPSetNodeIdFunc setNodeIdFunc = reinterpret_cast<GMPSetNodeIdFunc>(PR_FindFunctionSymbol(mLib, "GMPSetNodeId")); if (setNodeIdFunc) { setNodeIdFunc(nodeId.c_str(), nodeId.size()); } mGetAPIFunc = reinterpret_cast<GMPGetAPIFunc>(PR_FindFunctionSymbol(mLib, "GMPGetAPI")); if (!mGetAPIFunc) { return false; } return true; }
int main(int argc, char **argv) { int kl, l, fd, ac; int quiet = 0, hash = 0; char *av, *file = (char*)0; FILE *IN = (FILE*)0; SHA256_CTX ctx256; SHA384_CTX ctx384; SHA512_CTX ctx512; unsigned char buf[BUFLEN]; SHA256_Init(&ctx256); SHA384_Init(&ctx384); SHA512_Init(&ctx512); /* Read data from STDIN by default */ fd = fileno(stdin); ac = 1; while (ac < argc) { if (*argv[ac] == '-') { av = argv[ac] + 1; if (!strcmp(av, "q")) { quiet = 1; } else if (!strcmp(av, "256")) { hash |= 1; } else if (!strcmp(av, "384")) { hash |= 2; } else if (!strcmp(av, "512")) { hash |= 4; } else if (!strcmp(av, "ALL")) { hash = 7; } else { usage(argv[0], "Invalid option."); } ac++; } else { file = argv[ac++]; if (ac != argc) { usage(argv[0], "Too many arguments."); } if ((IN = fopen(file, "r")) == NULL) { perror(argv[0]); exit(-1); } fd = fileno(IN); } } if (hash == 0) hash = 7; /* Default to ALL */ kl = 0; while ((l = read(fd,buf,BUFLEN)) > 0) { kl += l; SHA256_Update(&ctx256, (unsigned char*)buf, l); SHA384_Update(&ctx384, (unsigned char*)buf, l); SHA512_Update(&ctx512, (unsigned char*)buf, l); } if (file) { fclose(IN); } if (hash & 1) { SHA256_End(&ctx256, buf); if (!quiet) printf("SHA-256 (%s) = ", file); printf("%s\n", buf); } if (hash & 2) { SHA384_End(&ctx384, buf); if (!quiet) printf("SHA-384 (%s) = ", file); printf("%s\n", buf); } if (hash & 4) { SHA512_End(&ctx512, buf); if (!quiet) printf("SHA-512 (%s) = ", file); printf("%s\n", buf); } return 1; }
/* ======================================================================== Routine Description: HMAC using SHA256 hash function Arguments: key Secret key key_len The length of the key in bytes message Message context message_len The length of message in bytes macLen Request the length of message authentication code Return Value: mac Message authentication code Note: None ======================================================================== */ VOID HMAC_SHA256 ( IN const UINT8 Key[], IN UINT KeyLen, IN const UINT8 Message[], IN UINT MessageLen, OUT UINT8 MAC[], IN UINT MACLen) { SHA256_CTX_STRUC sha_ctx1; SHA256_CTX_STRUC sha_ctx2; UINT8 K0[SHA256_BLOCK_SIZE]; UINT8 Digest[SHA256_DIGEST_SIZE]; UINT index; NdisZeroMemory(&sha_ctx1, sizeof(SHA256_CTX_STRUC)); NdisZeroMemory(&sha_ctx2, sizeof(SHA256_CTX_STRUC)); /* * If the length of K = B(Block size): K0 = K. * If the length of K > B: hash K to obtain an L byte string, * then append (B-L) zeros to create a B-byte string K0 (i.e., K0 = H(K) || 00...00). * If the length of K < B: append zeros to the end of K to create a B-byte string K0 */ NdisZeroMemory(K0, SHA256_BLOCK_SIZE); if (KeyLen <= SHA256_BLOCK_SIZE) { NdisMoveMemory(K0, Key, KeyLen); } else { RT_SHA256(Key, KeyLen, K0); } /* Exclusive-Or K0 with ipad */ /* ipad: Inner pad; the byte x��36�� repeated B times. */ for (index = 0; index < SHA256_BLOCK_SIZE; index++) K0[index] ^= 0x36; /* End of for */ SHA256_Init(&sha_ctx1); /* H(K0^ipad) */ SHA256_Append(&sha_ctx1, K0, sizeof(K0)); /* H((K0^ipad)||text) */ SHA256_Append(&sha_ctx1, Message, MessageLen); SHA256_End(&sha_ctx1, Digest); /* Exclusive-Or K0 with opad and remove ipad */ /* opad: Outer pad; the byte x��5c�� repeated B times. */ for (index = 0; index < SHA256_BLOCK_SIZE; index++) K0[index] ^= 0x36^0x5c; /* End of for */ SHA256_Init(&sha_ctx2); /* H(K0^opad) */ SHA256_Append(&sha_ctx2, K0, sizeof(K0)); /* H( (K0^opad) || H((K0^ipad)||text) ) */ SHA256_Append(&sha_ctx2, Digest, SHA256_DIGEST_SIZE); SHA256_End(&sha_ctx2, Digest); if (MACLen > SHA256_DIGEST_SIZE) NdisMoveMemory(MAC, Digest,SHA256_DIGEST_SIZE); else NdisMoveMemory(MAC, Digest, MACLen); } /* End of HMAC_SHA256 */
/* * Generates new random bytes and advances the internal prng state. * additional bytes are only used in algorithm testing. * * This function is specified in NIST SP 800-90 section 10.1.1.4 */ static SECStatus prng_generateNewBytes(RNGContext *rng, PRUint8 *returned_bytes, unsigned int no_of_returned_bytes, const PRUint8 *additional_input, unsigned int additional_input_len) { PRUint8 H[SHA256_LENGTH]; /* both H and w since they * aren't used concurrently */ unsigned int carry; if (!rng->isValid) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } /* This code only triggers during tests, normal * prng operation does not use additional_input */ if (additional_input){ SHA256Context ctx; /* NIST SP 800-90 defines two temporaries in their calculations, * w and H. These temporaries are the same lengths, and used * at different times, so we use the following macro to collapse * them to the same variable, but keeping their unique names for * easy comparison to the spec */ #define w H rng->V_type = prngAdditionalDataType; SHA256_Begin(&ctx); SHA256_Update(&ctx, rng->V_Data, sizeof rng->V_Data); SHA256_Update(&ctx, additional_input, additional_input_len); SHA256_End(&ctx, w, NULL, sizeof w); PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), w, sizeof w, carry) PORT_Memset(w, 0, sizeof w); #undef w } if (no_of_returned_bytes == SHA256_LENGTH) { /* short_cut to hashbuf and a couple of copies and clears */ SHA256_HashBuf(returned_bytes, V(rng), VSize(rng) ); /* continuous rng check */ if (memcmp(rng->lastOutput, returned_bytes, SHA256_LENGTH) == 0) { rng->isValid = PR_FALSE; } PORT_Memcpy(rng->lastOutput, returned_bytes, sizeof rng->lastOutput); } else { prng_Hashgen(rng, returned_bytes, no_of_returned_bytes); } /* advance our internal state... */ rng->V_type = prngGenerateByteType; SHA256_HashBuf(H, rng->V_Data, sizeof rng->V_Data); PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), H, sizeof H, carry) PRNG_ADD_BITS(V(rng), VSize(rng), rng->C, sizeof rng->C, carry); PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), rng->reseed_counter, sizeof rng->reseed_counter, carry) carry = 1; PRNG_ADD_CARRY_ONLY(rng->reseed_counter,(sizeof rng->reseed_counter)-1, carry); /* if the prng failed, don't return any output, signal softoken */ if (!rng->isValid) { PORT_Memset(returned_bytes, 0, no_of_returned_bytes); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } return SECSuccess; }