michael@0: /* vim:set ts=2 sw=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "prlog.h" michael@0: michael@0: #include "nsNTLMAuthModule.h" michael@0: #include "nsNSSShutDown.h" michael@0: #include "nsNativeCharsetUtils.h" michael@0: #include "prsystem.h" michael@0: #include "pk11pub.h" michael@0: #include "md4.h" michael@0: #include "mozilla/Likely.h" michael@0: #include "mozilla/Telemetry.h" michael@0: #include "mozilla/Preferences.h" michael@0: michael@0: #ifdef PR_LOGGING michael@0: static PRLogModuleInfo * michael@0: GetNTLMLog() michael@0: { michael@0: static PRLogModuleInfo *sNTLMLog; michael@0: if (!sNTLMLog) michael@0: sNTLMLog = PR_NewLogModule("NTLM"); michael@0: return sNTLMLog; michael@0: } michael@0: michael@0: #define LOG(x) PR_LOG(GetNTLMLog(), PR_LOG_DEBUG, x) michael@0: #define LOG_ENABLED() PR_LOG_TEST(GetNTLMLog(), PR_LOG_DEBUG) michael@0: #else michael@0: #define LOG(x) michael@0: #endif michael@0: michael@0: static void des_makekey(const uint8_t *raw, uint8_t *key); michael@0: static void des_encrypt(const uint8_t *key, const uint8_t *src, uint8_t *hash); michael@0: static void md5sum(const uint8_t *input, uint32_t inputLen, uint8_t *result); michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // this file contains a cross-platform NTLM authentication implementation. it michael@0: // is based on documentation from: http://davenport.sourceforge.net/ntlm.html michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: #define NTLM_NegotiateUnicode 0x00000001 michael@0: #define NTLM_NegotiateOEM 0x00000002 michael@0: #define NTLM_RequestTarget 0x00000004 michael@0: #define NTLM_Unknown1 0x00000008 michael@0: #define NTLM_NegotiateSign 0x00000010 michael@0: #define NTLM_NegotiateSeal 0x00000020 michael@0: #define NTLM_NegotiateDatagramStyle 0x00000040 michael@0: #define NTLM_NegotiateLanManagerKey 0x00000080 michael@0: #define NTLM_NegotiateNetware 0x00000100 michael@0: #define NTLM_NegotiateNTLMKey 0x00000200 michael@0: #define NTLM_Unknown2 0x00000400 michael@0: #define NTLM_Unknown3 0x00000800 michael@0: #define NTLM_NegotiateDomainSupplied 0x00001000 michael@0: #define NTLM_NegotiateWorkstationSupplied 0x00002000 michael@0: #define NTLM_NegotiateLocalCall 0x00004000 michael@0: #define NTLM_NegotiateAlwaysSign 0x00008000 michael@0: #define NTLM_TargetTypeDomain 0x00010000 michael@0: #define NTLM_TargetTypeServer 0x00020000 michael@0: #define NTLM_TargetTypeShare 0x00040000 michael@0: #define NTLM_NegotiateNTLM2Key 0x00080000 michael@0: #define NTLM_RequestInitResponse 0x00100000 michael@0: #define NTLM_RequestAcceptResponse 0x00200000 michael@0: #define NTLM_RequestNonNTSessionKey 0x00400000 michael@0: #define NTLM_NegotiateTargetInfo 0x00800000 michael@0: #define NTLM_Unknown4 0x01000000 michael@0: #define NTLM_Unknown5 0x02000000 michael@0: #define NTLM_Unknown6 0x04000000 michael@0: #define NTLM_Unknown7 0x08000000 michael@0: #define NTLM_Unknown8 0x10000000 michael@0: #define NTLM_Negotiate128 0x20000000 michael@0: #define NTLM_NegotiateKeyExchange 0x40000000 michael@0: #define NTLM_Negotiate56 0x80000000 michael@0: michael@0: // we send these flags with our type 1 message michael@0: #define NTLM_TYPE1_FLAGS \ michael@0: (NTLM_NegotiateUnicode | \ michael@0: NTLM_NegotiateOEM | \ michael@0: NTLM_RequestTarget | \ michael@0: NTLM_NegotiateNTLMKey | \ michael@0: NTLM_NegotiateAlwaysSign | \ michael@0: NTLM_NegotiateNTLM2Key) michael@0: michael@0: static const char NTLM_SIGNATURE[] = "NTLMSSP"; michael@0: static const char NTLM_TYPE1_MARKER[] = { 0x01, 0x00, 0x00, 0x00 }; michael@0: static const char NTLM_TYPE2_MARKER[] = { 0x02, 0x00, 0x00, 0x00 }; michael@0: static const char NTLM_TYPE3_MARKER[] = { 0x03, 0x00, 0x00, 0x00 }; michael@0: michael@0: #define NTLM_TYPE1_HEADER_LEN 32 michael@0: #define NTLM_TYPE2_HEADER_LEN 32 michael@0: #define NTLM_TYPE3_HEADER_LEN 64 michael@0: michael@0: #define LM_HASH_LEN 16 michael@0: #define LM_RESP_LEN 24 michael@0: michael@0: #define NTLM_HASH_LEN 16 michael@0: #define NTLM_RESP_LEN 24 michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: static bool sendLM = false; michael@0: michael@0: /*static*/ void michael@0: nsNTLMAuthModule::SetSendLM(bool newSendLM) michael@0: { michael@0: sendLM = newSendLM; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: #ifdef PR_LOGGING michael@0: michael@0: /** michael@0: * Prints a description of flags to the NSPR Log, if enabled. michael@0: */ michael@0: static void LogFlags(uint32_t flags) michael@0: { michael@0: if (!LOG_ENABLED()) michael@0: return; michael@0: #define TEST(_flag) \ michael@0: if (flags & NTLM_ ## _flag) \ michael@0: PR_LogPrint(" 0x%08x (" # _flag ")\n", NTLM_ ## _flag) michael@0: michael@0: TEST(NegotiateUnicode); michael@0: TEST(NegotiateOEM); michael@0: TEST(RequestTarget); michael@0: TEST(Unknown1); michael@0: TEST(NegotiateSign); michael@0: TEST(NegotiateSeal); michael@0: TEST(NegotiateDatagramStyle); michael@0: TEST(NegotiateLanManagerKey); michael@0: TEST(NegotiateNetware); michael@0: TEST(NegotiateNTLMKey); michael@0: TEST(Unknown2); michael@0: TEST(Unknown3); michael@0: TEST(NegotiateDomainSupplied); michael@0: TEST(NegotiateWorkstationSupplied); michael@0: TEST(NegotiateLocalCall); michael@0: TEST(NegotiateAlwaysSign); michael@0: TEST(TargetTypeDomain); michael@0: TEST(TargetTypeServer); michael@0: TEST(TargetTypeShare); michael@0: TEST(NegotiateNTLM2Key); michael@0: TEST(RequestInitResponse); michael@0: TEST(RequestAcceptResponse); michael@0: TEST(RequestNonNTSessionKey); michael@0: TEST(NegotiateTargetInfo); michael@0: TEST(Unknown4); michael@0: TEST(Unknown5); michael@0: TEST(Unknown6); michael@0: TEST(Unknown7); michael@0: TEST(Unknown8); michael@0: TEST(Negotiate128); michael@0: TEST(NegotiateKeyExchange); michael@0: TEST(Negotiate56); michael@0: michael@0: #undef TEST michael@0: } michael@0: michael@0: /** michael@0: * Prints a hexdump of buf to the NSPR Log, if enabled. michael@0: * @param tag Description of the data, will be printed in front of the data michael@0: * @param buf the data to print michael@0: * @param bufLen length of the data michael@0: */ michael@0: static void michael@0: LogBuf(const char *tag, const uint8_t *buf, uint32_t bufLen) michael@0: { michael@0: int i; michael@0: michael@0: if (!LOG_ENABLED()) michael@0: return; michael@0: michael@0: PR_LogPrint("%s =\n", tag); michael@0: char line[80]; michael@0: while (bufLen > 0) michael@0: { michael@0: int count = bufLen; michael@0: if (count > 8) michael@0: count = 8; michael@0: michael@0: strcpy(line, " "); michael@0: for (i=0; i> 8) & 0xff)) michael@0: #define SWAP32(x) ((SWAP16((x) & 0xffff) << 16) | (SWAP16((x) >> 16))) michael@0: michael@0: static void * michael@0: WriteBytes(void *buf, const void *data, uint32_t dataLen) michael@0: { michael@0: memcpy(buf, data, dataLen); michael@0: return (uint8_t *) buf + dataLen; michael@0: } michael@0: michael@0: static void * michael@0: WriteDWORD(void *buf, uint32_t dword) michael@0: { michael@0: #ifdef IS_BIG_ENDIAN michael@0: // NTLM uses little endian on the wire michael@0: dword = SWAP32(dword); michael@0: #endif michael@0: return WriteBytes(buf, &dword, sizeof(dword)); michael@0: } michael@0: michael@0: static void * michael@0: WriteSecBuf(void *buf, uint16_t length, uint32_t offset) michael@0: { michael@0: #ifdef IS_BIG_ENDIAN michael@0: length = SWAP16(length); michael@0: offset = SWAP32(offset); michael@0: #endif michael@0: buf = WriteBytes(buf, &length, sizeof(length)); michael@0: buf = WriteBytes(buf, &length, sizeof(length)); michael@0: buf = WriteBytes(buf, &offset, sizeof(offset)); michael@0: return buf; michael@0: } michael@0: michael@0: #ifdef IS_BIG_ENDIAN michael@0: /** michael@0: * WriteUnicodeLE copies a unicode string from one buffer to another. The michael@0: * resulting unicode string is in little-endian format. The input string is michael@0: * assumed to be in the native endianness of the local machine. It is safe michael@0: * to pass the same buffer as both input and output, which is a handy way to michael@0: * convert the unicode buffer to little-endian on big-endian platforms. michael@0: */ michael@0: static void * michael@0: WriteUnicodeLE(void *buf, const char16_t *str, uint32_t strLen) michael@0: { michael@0: // convert input string from BE to LE michael@0: uint8_t *cursor = (uint8_t *) buf, michael@0: *input = (uint8_t *) str; michael@0: for (uint32_t i=0; itargetLen = targetLen; michael@0: msg->target = ((const uint8_t *) inBuf) + offset; michael@0: } michael@0: else michael@0: { michael@0: // Do not error out, for (conservative) backward compatibility. michael@0: msg->targetLen = 0; michael@0: msg->target = nullptr; michael@0: } michael@0: michael@0: // read flags michael@0: msg->flags = ReadUint32(cursor); michael@0: michael@0: // read challenge michael@0: memcpy(msg->challenge, cursor, sizeof(msg->challenge)); michael@0: cursor += sizeof(msg->challenge); michael@0: michael@0: michael@0: LOG(("NTLM type 2 message:\n")); michael@0: LogBuf("target", (const uint8_t *) msg->target, msg->targetLen); michael@0: LogBuf("flags", (const uint8_t *) &msg->flags, 4); michael@0: LogFlags(msg->flags); michael@0: LogBuf("challenge", msg->challenge, sizeof(msg->challenge)); michael@0: michael@0: // we currently do not implement LMv2/NTLMv2 or NTLM2 responses, michael@0: // so we can ignore target information. we may want to enable michael@0: // support for these alternate mechanisms in the future. michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: GenerateType3Msg(const nsString &domain, michael@0: const nsString &username, michael@0: const nsString &password, michael@0: const void *inBuf, michael@0: uint32_t inLen, michael@0: void **outBuf, michael@0: uint32_t *outLen) michael@0: { michael@0: // inBuf contains Type-2 msg (the challenge) from server michael@0: michael@0: nsresult rv; michael@0: Type2Msg msg; michael@0: michael@0: rv = ParseType2Msg(inBuf, inLen, &msg); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: bool unicode = (msg.flags & NTLM_NegotiateUnicode); michael@0: michael@0: // temporary buffers for unicode strings michael@0: #ifdef IS_BIG_ENDIAN michael@0: nsAutoString ucsDomainBuf, ucsUserBuf; michael@0: #endif michael@0: nsAutoString ucsHostBuf; michael@0: // temporary buffers for oem strings michael@0: nsAutoCString oemDomainBuf, oemUserBuf, oemHostBuf; michael@0: // pointers and lengths for the string buffers; encoding is unicode if michael@0: // the "negotiate unicode" flag was set in the Type-2 message. michael@0: const void *domainPtr, *userPtr, *hostPtr; michael@0: uint32_t domainLen, userLen, hostLen; michael@0: michael@0: // michael@0: // get domain name michael@0: // michael@0: if (unicode) michael@0: { michael@0: #ifdef IS_BIG_ENDIAN michael@0: ucsDomainBuf = domain; michael@0: domainPtr = ucsDomainBuf.get(); michael@0: domainLen = ucsDomainBuf.Length() * 2; michael@0: WriteUnicodeLE((void *) domainPtr, (const char16_t *) domainPtr, michael@0: ucsDomainBuf.Length()); michael@0: #else michael@0: domainPtr = domain.get(); michael@0: domainLen = domain.Length() * 2; michael@0: #endif michael@0: } michael@0: else michael@0: { michael@0: NS_CopyUnicodeToNative(domain, oemDomainBuf); michael@0: domainPtr = oemDomainBuf.get(); michael@0: domainLen = oemDomainBuf.Length(); michael@0: } michael@0: michael@0: // michael@0: // get user name michael@0: // michael@0: if (unicode) michael@0: { michael@0: #ifdef IS_BIG_ENDIAN michael@0: ucsUserBuf = username; michael@0: userPtr = ucsUserBuf.get(); michael@0: userLen = ucsUserBuf.Length() * 2; michael@0: WriteUnicodeLE((void *) userPtr, (const char16_t *) userPtr, michael@0: ucsUserBuf.Length()); michael@0: #else michael@0: userPtr = username.get(); michael@0: userLen = username.Length() * 2; michael@0: #endif michael@0: } michael@0: else michael@0: { michael@0: NS_CopyUnicodeToNative(username, oemUserBuf); michael@0: userPtr = oemUserBuf.get(); michael@0: userLen = oemUserBuf.Length(); michael@0: } michael@0: michael@0: // michael@0: // get workstation name (use local machine's hostname) michael@0: // michael@0: char hostBuf[SYS_INFO_BUFFER_LENGTH]; michael@0: if (PR_GetSystemInfo(PR_SI_HOSTNAME, hostBuf, sizeof(hostBuf)) == PR_FAILURE) michael@0: return NS_ERROR_UNEXPECTED; michael@0: hostLen = strlen(hostBuf); michael@0: if (unicode) michael@0: { michael@0: // hostname is ASCII, so we can do a simple zero-pad expansion: michael@0: CopyASCIItoUTF16(nsDependentCString(hostBuf, hostLen), ucsHostBuf); michael@0: hostPtr = ucsHostBuf.get(); michael@0: hostLen = ucsHostBuf.Length() * 2; michael@0: #ifdef IS_BIG_ENDIAN michael@0: WriteUnicodeLE((void *) hostPtr, (const char16_t *) hostPtr, michael@0: ucsHostBuf.Length()); michael@0: #endif michael@0: } michael@0: else michael@0: hostPtr = hostBuf; michael@0: michael@0: // michael@0: // now that we have generated all of the strings, we can allocate outBuf. michael@0: // michael@0: *outLen = NTLM_TYPE3_HEADER_LEN + hostLen + domainLen + userLen + michael@0: LM_RESP_LEN + NTLM_RESP_LEN; michael@0: *outBuf = nsMemory::Alloc(*outLen); michael@0: if (!*outBuf) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: // michael@0: // next, we compute the LM and NTLM responses. michael@0: // michael@0: uint8_t lmResp[LM_RESP_LEN], ntlmResp[NTLM_RESP_LEN], ntlmHash[NTLM_HASH_LEN]; michael@0: if (msg.flags & NTLM_NegotiateNTLM2Key) michael@0: { michael@0: // compute NTLM2 session response michael@0: uint8_t sessionHash[16], temp[16]; michael@0: michael@0: PK11_GenerateRandom(lmResp, 8); michael@0: memset(lmResp + 8, 0, LM_RESP_LEN - 8); michael@0: michael@0: memcpy(temp, msg.challenge, 8); michael@0: memcpy(temp + 8, lmResp, 8); michael@0: md5sum(temp, 16, sessionHash); michael@0: michael@0: NTLM_Hash(password, ntlmHash); michael@0: LM_Response(ntlmHash, sessionHash, ntlmResp); michael@0: } michael@0: else michael@0: { michael@0: NTLM_Hash(password, ntlmHash); michael@0: LM_Response(ntlmHash, msg.challenge, ntlmResp); michael@0: michael@0: if (sendLM) michael@0: { michael@0: uint8_t lmHash[LM_HASH_LEN]; michael@0: LM_Hash(password, lmHash); michael@0: LM_Response(lmHash, msg.challenge, lmResp); michael@0: } michael@0: else michael@0: { michael@0: // According to http://davenport.sourceforge.net/ntlm.html#ntlmVersion2, michael@0: // the correct way to not send the LM hash is to send the NTLM hash twice michael@0: // in both the LM and NTLM response fields. michael@0: LM_Response(ntlmHash, msg.challenge, lmResp); michael@0: } michael@0: } michael@0: michael@0: // michael@0: // finally, we assemble the Type-3 msg :-) michael@0: // michael@0: void *cursor = *outBuf; michael@0: uint32_t offset; michael@0: michael@0: // 0 : signature michael@0: cursor = WriteBytes(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)); michael@0: michael@0: // 8 : marker michael@0: cursor = WriteBytes(cursor, NTLM_TYPE3_MARKER, sizeof(NTLM_TYPE3_MARKER)); michael@0: michael@0: // 12 : LM response sec buf michael@0: offset = NTLM_TYPE3_HEADER_LEN + domainLen + userLen + hostLen; michael@0: cursor = WriteSecBuf(cursor, LM_RESP_LEN, offset); michael@0: memcpy((uint8_t *) *outBuf + offset, lmResp, LM_RESP_LEN); michael@0: michael@0: // 20 : NTLM response sec buf michael@0: offset += LM_RESP_LEN; michael@0: cursor = WriteSecBuf(cursor, NTLM_RESP_LEN, offset); michael@0: memcpy((uint8_t *) *outBuf + offset, ntlmResp, NTLM_RESP_LEN); michael@0: michael@0: // 28 : domain name sec buf michael@0: offset = NTLM_TYPE3_HEADER_LEN; michael@0: cursor = WriteSecBuf(cursor, domainLen, offset); michael@0: memcpy((uint8_t *) *outBuf + offset, domainPtr, domainLen); michael@0: michael@0: // 36 : user name sec buf michael@0: offset += domainLen; michael@0: cursor = WriteSecBuf(cursor, userLen, offset); michael@0: memcpy((uint8_t *) *outBuf + offset, userPtr, userLen); michael@0: michael@0: // 44 : workstation (host) name sec buf michael@0: offset += userLen; michael@0: cursor = WriteSecBuf(cursor, hostLen, offset); michael@0: memcpy((uint8_t *) *outBuf + offset, hostPtr, hostLen); michael@0: michael@0: // 52 : session key sec buf (not used) michael@0: cursor = WriteSecBuf(cursor, 0, 0); michael@0: michael@0: // 60 : negotiated flags michael@0: cursor = WriteDWORD(cursor, msg.flags & NTLM_TYPE1_FLAGS); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: NS_IMPL_ISUPPORTS(nsNTLMAuthModule, nsIAuthModule) michael@0: michael@0: nsNTLMAuthModule::~nsNTLMAuthModule() michael@0: { michael@0: ZapString(mPassword); michael@0: } michael@0: michael@0: nsresult michael@0: nsNTLMAuthModule::InitTest() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: // michael@0: // disable NTLM authentication when FIPS mode is enabled. michael@0: // michael@0: return PK11_IsFIPS() ? NS_ERROR_NOT_AVAILABLE : NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNTLMAuthModule::Init(const char *serviceName, michael@0: uint32_t serviceFlags, michael@0: const char16_t *domain, michael@0: const char16_t *username, michael@0: const char16_t *password) michael@0: { michael@0: NS_ASSERTION((serviceFlags & ~nsIAuthModule::REQ_PROXY_AUTH) == nsIAuthModule::REQ_DEFAULT, michael@0: "unexpected service flags"); michael@0: michael@0: mDomain = domain; michael@0: mUsername = username; michael@0: mPassword = password; michael@0: michael@0: static bool sTelemetrySent = false; michael@0: if (!sTelemetrySent) { michael@0: mozilla::Telemetry::Accumulate( michael@0: mozilla::Telemetry::NTLM_MODULE_USED_2, michael@0: serviceFlags & nsIAuthModule::REQ_PROXY_AUTH michael@0: ? NTLM_MODULE_GENERIC_PROXY michael@0: : NTLM_MODULE_GENERIC_DIRECT); michael@0: sTelemetrySent = true; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNTLMAuthModule::GetNextToken(const void *inToken, michael@0: uint32_t inTokenLen, michael@0: void **outToken, michael@0: uint32_t *outTokenLen) michael@0: { michael@0: nsresult rv; michael@0: nsNSSShutDownPreventionLock locker; michael@0: // michael@0: // disable NTLM authentication when FIPS mode is enabled. michael@0: // michael@0: if (PK11_IsFIPS()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: // if inToken is non-null, then assume it contains a type 2 message... michael@0: if (inToken) michael@0: { michael@0: LogToken("in-token", inToken, inTokenLen); michael@0: rv = GenerateType3Msg(mDomain, mUsername, mPassword, inToken, michael@0: inTokenLen, outToken, outTokenLen); michael@0: } michael@0: else michael@0: { michael@0: rv = GenerateType1Msg(outToken, outTokenLen); michael@0: } michael@0: michael@0: #ifdef PR_LOGGING michael@0: if (NS_SUCCEEDED(rv)) michael@0: LogToken("out-token", *outToken, *outTokenLen); michael@0: #endif michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNTLMAuthModule::Unwrap(const void *inToken, michael@0: uint32_t inTokenLen, michael@0: void **outToken, michael@0: uint32_t *outTokenLen) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNTLMAuthModule::Wrap(const void *inToken, michael@0: uint32_t inTokenLen, michael@0: bool confidential, michael@0: void **outToken, michael@0: uint32_t *outTokenLen) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // DES support code michael@0: michael@0: // set odd parity bit (in least significant bit position) michael@0: static uint8_t michael@0: des_setkeyparity(uint8_t x) michael@0: { michael@0: if ((((x >> 7) ^ (x >> 6) ^ (x >> 5) ^ michael@0: (x >> 4) ^ (x >> 3) ^ (x >> 2) ^ michael@0: (x >> 1)) & 0x01) == 0) michael@0: x |= 0x01; michael@0: else michael@0: x &= 0xfe; michael@0: return x; michael@0: } michael@0: michael@0: // build 64-bit des key from 56-bit raw key michael@0: static void michael@0: des_makekey(const uint8_t *raw, uint8_t *key) michael@0: { michael@0: key[0] = des_setkeyparity(raw[0]); michael@0: key[1] = des_setkeyparity((raw[0] << 7) | (raw[1] >> 1)); michael@0: key[2] = des_setkeyparity((raw[1] << 6) | (raw[2] >> 2)); michael@0: key[3] = des_setkeyparity((raw[2] << 5) | (raw[3] >> 3)); michael@0: key[4] = des_setkeyparity((raw[3] << 4) | (raw[4] >> 4)); michael@0: key[5] = des_setkeyparity((raw[4] << 3) | (raw[5] >> 5)); michael@0: key[6] = des_setkeyparity((raw[5] << 2) | (raw[6] >> 6)); michael@0: key[7] = des_setkeyparity((raw[6] << 1)); michael@0: } michael@0: michael@0: // run des encryption algorithm (using NSS) michael@0: static void michael@0: des_encrypt(const uint8_t *key, const uint8_t *src, uint8_t *hash) michael@0: { michael@0: CK_MECHANISM_TYPE cipherMech = CKM_DES_ECB; michael@0: PK11SlotInfo *slot = nullptr; michael@0: PK11SymKey *symkey = nullptr; michael@0: PK11Context *ctxt = nullptr; michael@0: SECItem keyItem, *param = nullptr; michael@0: SECStatus rv; michael@0: unsigned int n; michael@0: michael@0: slot = PK11_GetBestSlot(cipherMech, nullptr); michael@0: if (!slot) michael@0: { michael@0: NS_ERROR("no slot"); michael@0: goto done; michael@0: } michael@0: michael@0: keyItem.data = (uint8_t *) key; michael@0: keyItem.len = 8; michael@0: symkey = PK11_ImportSymKey(slot, cipherMech, michael@0: PK11_OriginUnwrap, CKA_ENCRYPT, michael@0: &keyItem, nullptr); michael@0: if (!symkey) michael@0: { michael@0: NS_ERROR("no symkey"); michael@0: goto done; michael@0: } michael@0: michael@0: // no initialization vector required michael@0: param = PK11_ParamFromIV(cipherMech, nullptr); michael@0: if (!param) michael@0: { michael@0: NS_ERROR("no param"); michael@0: goto done; michael@0: } michael@0: michael@0: ctxt = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT, michael@0: symkey, param); michael@0: if (!ctxt) michael@0: { michael@0: NS_ERROR("no context"); michael@0: goto done; michael@0: } michael@0: michael@0: rv = PK11_CipherOp(ctxt, hash, (int *) &n, 8, (uint8_t *) src, 8); michael@0: if (rv != SECSuccess) michael@0: { michael@0: NS_ERROR("des failure"); michael@0: goto done; michael@0: } michael@0: michael@0: rv = PK11_DigestFinal(ctxt, hash+8, &n, 0); michael@0: if (rv != SECSuccess) michael@0: { michael@0: NS_ERROR("des failure"); michael@0: goto done; michael@0: } michael@0: michael@0: done: michael@0: if (ctxt) michael@0: PK11_DestroyContext(ctxt, true); michael@0: if (symkey) michael@0: PK11_FreeSymKey(symkey); michael@0: if (param) michael@0: SECITEM_FreeItem(param, true); michael@0: if (slot) michael@0: PK11_FreeSlot(slot); michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // MD5 support code michael@0: michael@0: static void md5sum(const uint8_t *input, uint32_t inputLen, uint8_t *result) michael@0: { michael@0: PK11Context *ctxt = PK11_CreateDigestContext(SEC_OID_MD5); michael@0: if (ctxt) michael@0: { michael@0: if (PK11_DigestBegin(ctxt) == SECSuccess) michael@0: { michael@0: if (PK11_DigestOp(ctxt, input, inputLen) == SECSuccess) michael@0: { michael@0: uint32_t resultLen = 16; michael@0: PK11_DigestFinal(ctxt, result, &resultLen, resultLen); michael@0: } michael@0: } michael@0: PK11_DestroyContext(ctxt, true); michael@0: } michael@0: }