Blame libfreerdp/core/security.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * RDP Security
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 * Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include "security.h"
Packit Service fa4841
Packit Service fa4841
#include <freerdp/log.h>
Packit Service fa4841
#include <winpr/crypto.h>
Packit Service fa4841
Packit Service fa4841
#define TAG FREERDP_TAG("core")
Packit Service fa4841
Packit Service fa4841
/* 0x36 repeated 40 times */
Packit Service fa4841
static const BYTE pad1[40] = { "\x36\x36\x36\x36\x36\x36\x36\x36"
Packit Service fa4841
	                           "\x36\x36\x36\x36\x36\x36\x36\x36"
Packit Service fa4841
	                           "\x36\x36\x36\x36\x36\x36\x36\x36"
Packit Service fa4841
	                           "\x36\x36\x36\x36\x36\x36\x36\x36"
Packit Service fa4841
	                           "\x36\x36\x36\x36\x36\x36\x36\x36" };
Packit Service fa4841
Packit Service fa4841
/* 0x5C repeated 48 times */
Packit Service fa4841
static const BYTE pad2[48] = { "\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C"
Packit Service fa4841
	                           "\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C"
Packit Service fa4841
	                           "\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C"
Packit Service fa4841
	                           "\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C"
Packit Service fa4841
	                           "\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C"
Packit Service fa4841
	                           "\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C" };
Packit Service fa4841
Packit Service fa4841
static const BYTE fips_reverse_table[256] = {
Packit Service fa4841
	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
Packit Service fa4841
	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
Packit Service fa4841
	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
Packit Service fa4841
	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
Packit Service fa4841
	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
Packit Service fa4841
	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
Packit Service fa4841
	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
Packit Service fa4841
	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
Packit Service fa4841
	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
Packit Service fa4841
	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
Packit Service fa4841
	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
Packit Service fa4841
	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
Packit Service fa4841
	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
Packit Service fa4841
	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
Packit Service fa4841
	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
Packit Service fa4841
	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
Packit Service fa4841
};
Packit Service fa4841
Packit Service fa4841
static const BYTE fips_oddparity_table[256] = {
Packit Service fa4841
	0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, 0x08, 0x08, 0x0b, 0x0b, 0x0d, 0x0d, 0x0e, 0x0e,
Packit Service fa4841
	0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, 0x19, 0x19, 0x1a, 0x1a, 0x1c, 0x1c, 0x1f, 0x1f,
Packit Service fa4841
	0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26, 0x29, 0x29, 0x2a, 0x2a, 0x2c, 0x2c, 0x2f, 0x2f,
Packit Service fa4841
	0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, 0x38, 0x38, 0x3b, 0x3b, 0x3d, 0x3d, 0x3e, 0x3e,
Packit Service fa4841
	0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, 0x49, 0x49, 0x4a, 0x4a, 0x4c, 0x4c, 0x4f, 0x4f,
Packit Service fa4841
	0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57, 0x58, 0x58, 0x5b, 0x5b, 0x5d, 0x5d, 0x5e, 0x5e,
Packit Service fa4841
	0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, 0x68, 0x68, 0x6b, 0x6b, 0x6d, 0x6d, 0x6e, 0x6e,
Packit Service fa4841
	0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, 0x79, 0x79, 0x7a, 0x7a, 0x7c, 0x7c, 0x7f, 0x7f,
Packit Service fa4841
	0x80, 0x80, 0x83, 0x83, 0x85, 0x85, 0x86, 0x86, 0x89, 0x89, 0x8a, 0x8a, 0x8c, 0x8c, 0x8f, 0x8f,
Packit Service fa4841
	0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97, 0x98, 0x98, 0x9b, 0x9b, 0x9d, 0x9d, 0x9e, 0x9e,
Packit Service fa4841
	0xa1, 0xa1, 0xa2, 0xa2, 0xa4, 0xa4, 0xa7, 0xa7, 0xa8, 0xa8, 0xab, 0xab, 0xad, 0xad, 0xae, 0xae,
Packit Service fa4841
	0xb0, 0xb0, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb6, 0xb9, 0xb9, 0xba, 0xba, 0xbc, 0xbc, 0xbf, 0xbf,
Packit Service fa4841
	0xc1, 0xc1, 0xc2, 0xc2, 0xc4, 0xc4, 0xc7, 0xc7, 0xc8, 0xc8, 0xcb, 0xcb, 0xcd, 0xcd, 0xce, 0xce,
Packit Service fa4841
	0xd0, 0xd0, 0xd3, 0xd3, 0xd5, 0xd5, 0xd6, 0xd6, 0xd9, 0xd9, 0xda, 0xda, 0xdc, 0xdc, 0xdf, 0xdf,
Packit Service fa4841
	0xe0, 0xe0, 0xe3, 0xe3, 0xe5, 0xe5, 0xe6, 0xe6, 0xe9, 0xe9, 0xea, 0xea, 0xec, 0xec, 0xef, 0xef,
Packit Service fa4841
	0xf1, 0xf1, 0xf2, 0xf2, 0xf4, 0xf4, 0xf7, 0xf7, 0xf8, 0xf8, 0xfb, 0xfb, 0xfd, 0xfd, 0xfe, 0xfe
Packit Service fa4841
};
Packit Service fa4841
Packit Service fa4841
static BOOL security_salted_hash(const BYTE* salt, const BYTE* input, int length, const BYTE* salt1,
Packit Service fa4841
                                 const BYTE* salt2, BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	WINPR_DIGEST_CTX* sha1 = NULL;
Packit Service fa4841
	WINPR_DIGEST_CTX* md5 = NULL;
Packit Service fa4841
	BYTE sha1_digest[WINPR_SHA1_DIGEST_LENGTH];
Packit Service fa4841
	BOOL result = FALSE;
Packit Service fa4841
Packit Service fa4841
	/* SaltedHash(Salt, Input, Salt1, Salt2) = MD5(S + SHA1(Input + Salt + Salt1 + Salt2)) */
Packit Service fa4841
Packit Service fa4841
	/* SHA1_Digest = SHA1(Input + Salt + Salt1 + Salt2) */
Packit Service fa4841
	if (!(sha1 = winpr_Digest_New()))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Init(sha1, WINPR_MD_SHA1))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, input, length)) /* Input */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, salt, 48)) /* Salt (48 bytes) */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, salt1, 32)) /* Salt1 (32 bytes) */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, salt2, 32)) /* Salt2 (32 bytes) */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Final(sha1, sha1_digest, sizeof(sha1_digest)))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	/* SaltedHash(Salt, Input, Salt1, Salt2) = MD5(S + SHA1_Digest) */
Packit Service fa4841
	if (!(md5 = winpr_Digest_New()))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	/* Allow FIPS override for use of MD5 here, this is used for creating hashes of the
Packit Service fa4841
	 * premaster_secret and master_secret */
Packit Service fa4841
	/* used for RDP licensing as described in MS-RDPELE. This is for RDP licensing packets */
Packit Service fa4841
	/* which will already be encrypted under FIPS, so the use of MD5 here is not for sensitive data
Packit Service fa4841
	 * protection. */
Packit Service fa4841
	if (!winpr_Digest_Init_Allow_FIPS(md5, WINPR_MD_MD5))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, salt, 48)) /* Salt (48 bytes) */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, sha1_digest, sizeof(sha1_digest))) /* SHA1_Digest */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Final(md5, output, WINPR_MD5_DIGEST_LENGTH))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	result = TRUE;
Packit Service fa4841
out:
Packit Service fa4841
	winpr_Digest_Free(sha1);
Packit Service fa4841
	winpr_Digest_Free(md5);
Packit Service fa4841
	return result;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL security_premaster_hash(const char* input, int length, const BYTE* premaster_secret,
Packit Service fa4841
                                    const BYTE* client_random, const BYTE* server_random,
Packit Service fa4841
                                    BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	/* PremasterHash(Input) = SaltedHash(PremasterSecret, Input, ClientRandom, ServerRandom) */
Packit Service fa4841
	return security_salted_hash(premaster_secret, (BYTE*)input, length, client_random,
Packit Service fa4841
	                            server_random, output);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL security_master_secret(const BYTE* premaster_secret, const BYTE* client_random,
Packit Service fa4841
                            const BYTE* server_random, BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	/* MasterSecret = PremasterHash('A') + PremasterHash('BB') + PremasterHash('CCC') */
Packit Service fa4841
	return security_premaster_hash("A", 1, premaster_secret, client_random, server_random,
Packit Service fa4841
	                               &output[0]) &&
Packit Service fa4841
	       security_premaster_hash("BB", 2, premaster_secret, client_random, server_random,
Packit Service fa4841
	                               &output[16]) &&
Packit Service fa4841
	       security_premaster_hash("CCC", 3, premaster_secret, client_random, server_random,
Packit Service fa4841
	                               &output[32]);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL security_master_hash(const char* input, int length, const BYTE* master_secret,
Packit Service fa4841
                                 const BYTE* client_random, const BYTE* server_random, BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	/* MasterHash(Input) = SaltedHash(MasterSecret, Input, ServerRandom, ClientRandom) */
Packit Service fa4841
	return security_salted_hash(master_secret, (const BYTE*)input, length, server_random,
Packit Service fa4841
	                            client_random, output);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL security_session_key_blob(const BYTE* master_secret, const BYTE* client_random,
Packit Service fa4841
                               const BYTE* server_random, BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	/* MasterHash = MasterHash('A') + MasterHash('BB') + MasterHash('CCC') */
Packit Service fa4841
	return security_master_hash("A", 1, master_secret, client_random, server_random, &output[0]) &&
Packit Service fa4841
	       security_master_hash("BB", 2, master_secret, client_random, server_random,
Packit Service fa4841
	                            &output[16]) &&
Packit Service fa4841
	       security_master_hash("CCC", 3, master_secret, client_random, server_random, &output[32]);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void security_mac_salt_key(const BYTE* session_key_blob, const BYTE* client_random,
Packit Service fa4841
                           const BYTE* server_random, BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	/* MacSaltKey = First128Bits(SessionKeyBlob) */
Packit Service fa4841
	memcpy(output, session_key_blob, 16);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL security_md5_16_32_32(const BYTE* in0, const BYTE* in1, const BYTE* in2, BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	WINPR_DIGEST_CTX* md5 = NULL;
Packit Service fa4841
	BOOL result = FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!(md5 = winpr_Digest_New()))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Init(md5, WINPR_MD_MD5))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, in0, 16))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, in1, 32))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, in2, 32))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Final(md5, output, WINPR_MD5_DIGEST_LENGTH))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	result = TRUE;
Packit Service fa4841
out:
Packit Service fa4841
	winpr_Digest_Free(md5);
Packit Service fa4841
	return result;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL security_md5_16_32_32_Allow_FIPS(const BYTE* in0, const BYTE* in1, const BYTE* in2,
Packit Service fa4841
                                             BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	WINPR_DIGEST_CTX* md5 = NULL;
Packit Service fa4841
	BOOL result = FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!(md5 = winpr_Digest_New()))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	if (!winpr_Digest_Init_Allow_FIPS(md5, WINPR_MD_MD5))
Packit Service fa4841
		goto out;
Packit Service fa4841
	if (!winpr_Digest_Update(md5, in0, 16))
Packit Service fa4841
		goto out;
Packit Service fa4841
	if (!winpr_Digest_Update(md5, in1, 32))
Packit Service fa4841
		goto out;
Packit Service fa4841
	if (!winpr_Digest_Update(md5, in2, 32))
Packit Service fa4841
		goto out;
Packit Service fa4841
	if (!winpr_Digest_Final(md5, output, WINPR_MD5_DIGEST_LENGTH))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	result = TRUE;
Packit Service fa4841
out:
Packit Service fa4841
	winpr_Digest_Free(md5);
Packit Service fa4841
	return result;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL security_licensing_encryption_key(const BYTE* session_key_blob, const BYTE* client_random,
Packit Service fa4841
                                       const BYTE* server_random, BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	/* LicensingEncryptionKey = MD5(Second128Bits(SessionKeyBlob) + ClientRandom + ServerRandom))
Packit Service fa4841
	 * Allow FIPS use of MD5 here, this is just used for creating the licensing encryption key as
Packit Service fa4841
	 * described in MS-RDPELE. This is for RDP licensing packets which will already be encrypted
Packit Service fa4841
	 * under FIPS, so the use of MD5 here is not for sensitive data protection. */
Packit Service fa4841
	return security_md5_16_32_32_Allow_FIPS(&session_key_blob[16], client_random, server_random,
Packit Service fa4841
	                                        output);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void security_UINT32_le(BYTE* output, UINT32 value)
Packit Service fa4841
{
Packit Service fa4841
	output[0] = (value)&0xFF;
Packit Service fa4841
	output[1] = (value >> 8) & 0xFF;
Packit Service fa4841
	output[2] = (value >> 16) & 0xFF;
Packit Service fa4841
	output[3] = (value >> 24) & 0xFF;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL security_mac_data(const BYTE* mac_salt_key, const BYTE* data, UINT32 length, BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	WINPR_DIGEST_CTX* sha1 = NULL;
Packit Service fa4841
	WINPR_DIGEST_CTX* md5 = NULL;
Packit Service fa4841
	BYTE length_le[4];
Packit Service fa4841
	BYTE sha1_digest[WINPR_SHA1_DIGEST_LENGTH];
Packit Service fa4841
	BOOL result = FALSE;
Packit Service fa4841
	/* MacData = MD5(MacSaltKey + pad2 + SHA1(MacSaltKey + pad1 + length + data)) */
Packit Service fa4841
	security_UINT32_le(length_le, length); /* length must be little-endian */
Packit Service fa4841
Packit Service fa4841
	/* SHA1_Digest = SHA1(MacSaltKey + pad1 + length + data) */
Packit Service fa4841
	if (!(sha1 = winpr_Digest_New()))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Init(sha1, WINPR_MD_SHA1))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, mac_salt_key, 16)) /* MacSaltKey */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, pad1, sizeof(pad1))) /* pad1 */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, length_le, sizeof(length_le))) /* length */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, data, length)) /* data */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Final(sha1, sha1_digest, sizeof(sha1_digest)))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	/* MacData = MD5(MacSaltKey + pad2 + SHA1_Digest) */
Packit Service fa4841
	if (!(md5 = winpr_Digest_New()))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	/* Allow FIPS override for use of MD5 here, this is only used for creating the MACData field of
Packit Service fa4841
	 * the */
Packit Service fa4841
	/* Client Platform Challenge Response packet (from MS-RDPELE section 2.2.2.5). This is for RDP
Packit Service fa4841
	 * licensing packets */
Packit Service fa4841
	/* which will already be encrypted under FIPS, so the use of MD5 here is not for sensitive data
Packit Service fa4841
	 * protection. */
Packit Service fa4841
	if (!winpr_Digest_Init_Allow_FIPS(md5, WINPR_MD_MD5))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, mac_salt_key, 16)) /* MacSaltKey */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, pad2, sizeof(pad2))) /* pad2 */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, sha1_digest, sizeof(sha1_digest))) /* SHA1_Digest */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Final(md5, output, WINPR_MD5_DIGEST_LENGTH))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	result = TRUE;
Packit Service fa4841
out:
Packit Service fa4841
	winpr_Digest_Free(sha1);
Packit Service fa4841
	winpr_Digest_Free(md5);
Packit Service fa4841
	return result;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL security_mac_signature(rdpRdp* rdp, const BYTE* data, UINT32 length, BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	WINPR_DIGEST_CTX* sha1 = NULL;
Packit Service fa4841
	WINPR_DIGEST_CTX* md5 = NULL;
Packit Service fa4841
	BYTE length_le[4];
Packit Service fa4841
	BYTE md5_digest[WINPR_MD5_DIGEST_LENGTH];
Packit Service fa4841
	BYTE sha1_digest[WINPR_SHA1_DIGEST_LENGTH];
Packit Service fa4841
	BOOL result = FALSE;
Packit Service fa4841
	security_UINT32_le(length_le, length); /* length must be little-endian */
Packit Service fa4841
Packit Service fa4841
	/* SHA1_Digest = SHA1(MACKeyN + pad1 + length + data) */
Packit Service fa4841
	if (!(sha1 = winpr_Digest_New()))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Init(sha1, WINPR_MD_SHA1))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, rdp->sign_key, rdp->rc4_key_len)) /* MacKeyN */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, pad1, sizeof(pad1))) /* pad1 */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, length_le, sizeof(length_le))) /* length */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, data, length)) /* data */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Final(sha1, sha1_digest, sizeof(sha1_digest)))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	/* MACSignature = First64Bits(MD5(MACKeyN + pad2 + SHA1_Digest)) */
Packit Service fa4841
	if (!(md5 = winpr_Digest_New()))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Init(md5, WINPR_MD_MD5))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, rdp->sign_key, rdp->rc4_key_len)) /* MacKeyN */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, pad2, sizeof(pad2))) /* pad2 */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, sha1_digest, sizeof(sha1_digest))) /* SHA1_Digest */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Final(md5, md5_digest, sizeof(md5_digest)))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	memcpy(output, md5_digest, 8);
Packit Service fa4841
	result = TRUE;
Packit Service fa4841
out:
Packit Service fa4841
	winpr_Digest_Free(sha1);
Packit Service fa4841
	winpr_Digest_Free(md5);
Packit Service fa4841
	return result;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL security_salted_mac_signature(rdpRdp* rdp, const BYTE* data, UINT32 length, BOOL encryption,
Packit Service fa4841
                                   BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	WINPR_DIGEST_CTX* sha1 = NULL;
Packit Service fa4841
	WINPR_DIGEST_CTX* md5 = NULL;
Packit Service fa4841
	BYTE length_le[4];
Packit Service fa4841
	BYTE use_count_le[4];
Packit Service fa4841
	BYTE md5_digest[WINPR_MD5_DIGEST_LENGTH];
Packit Service fa4841
	BYTE sha1_digest[WINPR_SHA1_DIGEST_LENGTH];
Packit Service fa4841
	BOOL result = FALSE;
Packit Service fa4841
Packit Service fa4841
	EnterCriticalSection(&rdp->critical);
Packit Service fa4841
	security_UINT32_le(length_le, length); /* length must be little-endian */
Packit Service fa4841
Packit Service fa4841
	if (encryption)
Packit Service fa4841
	{
Packit Service fa4841
		security_UINT32_le(use_count_le, rdp->encrypt_checksum_use_count);
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		/*
Packit Service fa4841
		 * We calculate checksum on plain text, so we must have already
Packit Service fa4841
		 * decrypt it, which means decrypt_checksum_use_count is off by one.
Packit Service fa4841
		 */
Packit Service fa4841
		security_UINT32_le(use_count_le, rdp->decrypt_checksum_use_count - 1);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* SHA1_Digest = SHA1(MACKeyN + pad1 + length + data) */
Packit Service fa4841
	if (!(sha1 = winpr_Digest_New()))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Init(sha1, WINPR_MD_SHA1))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, rdp->sign_key, rdp->rc4_key_len)) /* MacKeyN */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, pad1, sizeof(pad1))) /* pad1 */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, length_le, sizeof(length_le))) /* length */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, data, length)) /* data */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, use_count_le, sizeof(use_count_le))) /* encryptionCount */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Final(sha1, sha1_digest, sizeof(sha1_digest)))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	/* MACSignature = First64Bits(MD5(MACKeyN + pad2 + SHA1_Digest)) */
Packit Service fa4841
	if (!(md5 = winpr_Digest_New()))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Init(md5, WINPR_MD_MD5))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, rdp->sign_key, rdp->rc4_key_len)) /* MacKeyN */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, pad2, sizeof(pad2))) /* pad2 */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, sha1_digest, sizeof(sha1_digest))) /* SHA1_Digest */
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Final(md5, md5_digest, sizeof(md5_digest)))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	memcpy(output, md5_digest, 8);
Packit Service fa4841
	result = TRUE;
Packit Service fa4841
out:
Packit Service fa4841
	LeaveCriticalSection(&rdp->critical);
Packit Service fa4841
	winpr_Digest_Free(sha1);
Packit Service fa4841
	winpr_Digest_Free(md5);
Packit Service fa4841
	return result;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL security_A(BYTE* master_secret, const BYTE* client_random, BYTE* server_random,
Packit Service fa4841
                       BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	return security_premaster_hash("A", 1, master_secret, client_random, server_random,
Packit Service fa4841
	                               &output[0]) &&
Packit Service fa4841
	       security_premaster_hash("BB", 2, master_secret, client_random, server_random,
Packit Service fa4841
	                               &output[16]) &&
Packit Service fa4841
	       security_premaster_hash("CCC", 3, master_secret, client_random, server_random,
Packit Service fa4841
	                               &output[32]);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL security_X(BYTE* master_secret, const BYTE* client_random, BYTE* server_random,
Packit Service fa4841
                       BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	return security_premaster_hash("X", 1, master_secret, client_random, server_random,
Packit Service fa4841
	                               &output[0]) &&
Packit Service fa4841
	       security_premaster_hash("YY", 2, master_secret, client_random, server_random,
Packit Service fa4841
	                               &output[16]) &&
Packit Service fa4841
	       security_premaster_hash("ZZZ", 3, master_secret, client_random, server_random,
Packit Service fa4841
	                               &output[32]);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void fips_expand_key_bits(BYTE* in, BYTE* out)
Packit Service fa4841
{
Packit Service fa4841
	BYTE buf[21], c;
Packit Service fa4841
	int i, b, p, r;
Packit Service fa4841
Packit Service fa4841
	/* reverse every byte in the key */
Packit Service fa4841
	for (i = 0; i < 21; i++)
Packit Service fa4841
		buf[i] = fips_reverse_table[in[i]];
Packit Service fa4841
Packit Service fa4841
	/* insert a zero-bit after every 7th bit */
Packit Service fa4841
	for (i = 0, b = 0; i < 24; i++, b += 7)
Packit Service fa4841
	{
Packit Service fa4841
		p = b / 8;
Packit Service fa4841
		r = b % 8;
Packit Service fa4841
Packit Service fa4841
		if (r <= 1)
Packit Service fa4841
		{
Packit Service fa4841
			out[i] = (buf[p] << r) & 0xfe;
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
		{
Packit Service fa4841
			/* c is accumulator */
Packit Service fa4841
			c = buf[p] << r;
Packit Service fa4841
			c |= buf[p + 1] >> (8 - r);
Packit Service fa4841
			out[i] = c & 0xfe;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* reverse every byte */
Packit Service fa4841
	/* alter lsb so the byte has odd parity */
Packit Service fa4841
	for (i = 0; i < 24; i++)
Packit Service fa4841
		out[i] = fips_oddparity_table[fips_reverse_table[out[i]]];
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp)
Packit Service fa4841
{
Packit Service fa4841
	BYTE pre_master_secret[48];
Packit Service fa4841
	BYTE master_secret[48];
Packit Service fa4841
	BYTE session_key_blob[48];
Packit Service fa4841
	BYTE* server_random;
Packit Service fa4841
	BYTE salt[] = { 0xD1, 0x26, 0x9E }; /* 40 bits: 3 bytes, 56 bits: 1 byte */
Packit Service fa4841
	rdpSettings* settings;
Packit Service fa4841
	BOOL status;
Packit Service fa4841
	settings = rdp->settings;
Packit Service fa4841
	server_random = settings->ServerRandom;
Packit Service fa4841
Packit Service fa4841
	if (settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
Packit Service fa4841
	{
Packit Service fa4841
		WINPR_DIGEST_CTX* sha1;
Packit Service fa4841
		BYTE client_encrypt_key_t[WINPR_SHA1_DIGEST_LENGTH + 1];
Packit Service fa4841
		BYTE client_decrypt_key_t[WINPR_SHA1_DIGEST_LENGTH + 1];
Packit Service fa4841
Packit Service fa4841
		if (!(sha1 = winpr_Digest_New()))
Packit Service fa4841
			return FALSE;
Packit Service fa4841
Packit Service fa4841
		if (!winpr_Digest_Init(sha1, WINPR_MD_SHA1) ||
Packit Service fa4841
		    !winpr_Digest_Update(sha1, client_random + 16, 16) ||
Packit Service fa4841
		    !winpr_Digest_Update(sha1, server_random + 16, 16) ||
Packit Service fa4841
		    !winpr_Digest_Final(sha1, client_encrypt_key_t, sizeof(client_encrypt_key_t)))
Packit Service fa4841
		{
Packit Service fa4841
			winpr_Digest_Free(sha1);
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		client_encrypt_key_t[20] = client_encrypt_key_t[0];
Packit Service fa4841
Packit Service fa4841
		if (!winpr_Digest_Init(sha1, WINPR_MD_SHA1) ||
Packit Service fa4841
		    !winpr_Digest_Update(sha1, client_random, 16) ||
Packit Service fa4841
		    !winpr_Digest_Update(sha1, server_random, 16) ||
Packit Service fa4841
		    !winpr_Digest_Final(sha1, client_decrypt_key_t, sizeof(client_decrypt_key_t)))
Packit Service fa4841
		{
Packit Service fa4841
			winpr_Digest_Free(sha1);
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		client_decrypt_key_t[20] = client_decrypt_key_t[0];
Packit Service fa4841
Packit Service fa4841
		if (!winpr_Digest_Init(sha1, WINPR_MD_SHA1) ||
Packit Service fa4841
		    !winpr_Digest_Update(sha1, client_decrypt_key_t, WINPR_SHA1_DIGEST_LENGTH) ||
Packit Service fa4841
		    !winpr_Digest_Update(sha1, client_encrypt_key_t, WINPR_SHA1_DIGEST_LENGTH) ||
Packit Service fa4841
		    !winpr_Digest_Final(sha1, rdp->fips_sign_key, WINPR_SHA1_DIGEST_LENGTH))
Packit Service fa4841
		{
Packit Service fa4841
			winpr_Digest_Free(sha1);
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		winpr_Digest_Free(sha1);
Packit Service fa4841
Packit Service fa4841
		if (rdp->settings->ServerMode)
Packit Service fa4841
		{
Packit Service fa4841
			fips_expand_key_bits(client_encrypt_key_t, rdp->fips_decrypt_key);
Packit Service fa4841
			fips_expand_key_bits(client_decrypt_key_t, rdp->fips_encrypt_key);
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
		{
Packit Service fa4841
			fips_expand_key_bits(client_encrypt_key_t, rdp->fips_encrypt_key);
Packit Service fa4841
			fips_expand_key_bits(client_decrypt_key_t, rdp->fips_decrypt_key);
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	memcpy(pre_master_secret, client_random, 24);
Packit Service fa4841
	memcpy(pre_master_secret + 24, server_random, 24);
Packit Service fa4841
Packit Service fa4841
	if (!security_A(pre_master_secret, client_random, server_random, master_secret) ||
Packit Service fa4841
	    !security_X(master_secret, client_random, server_random, session_key_blob))
Packit Service fa4841
	{
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	memcpy(rdp->sign_key, session_key_blob, 16);
Packit Service fa4841
Packit Service fa4841
	if (rdp->settings->ServerMode)
Packit Service fa4841
	{
Packit Service fa4841
		status = security_md5_16_32_32(&session_key_blob[16], client_random, server_random,
Packit Service fa4841
		                               rdp->encrypt_key);
Packit Service fa4841
		status &= security_md5_16_32_32(&session_key_blob[32], client_random, server_random,
Packit Service fa4841
		                                rdp->decrypt_key);
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		/* Allow FIPS use of MD5 here, this is just used for generation of the SessionKeyBlob as
Packit Service fa4841
		 * described in MS-RDPELE. */
Packit Service fa4841
		/* This is for RDP licensing packets which will already be encrypted under FIPS, so the use
Packit Service fa4841
		 * of MD5 here is not */
Packit Service fa4841
		/* for sensitive data protection. */
Packit Service fa4841
		status = security_md5_16_32_32_Allow_FIPS(&session_key_blob[16], client_random,
Packit Service fa4841
		                                          server_random, rdp->decrypt_key);
Packit Service fa4841
		status &= security_md5_16_32_32_Allow_FIPS(&session_key_blob[32], client_random,
Packit Service fa4841
		                                           server_random, rdp->encrypt_key);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!status)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (settings->EncryptionMethods == ENCRYPTION_METHOD_40BIT)
Packit Service fa4841
	{
Packit Service fa4841
		memcpy(rdp->sign_key, salt, 3);
Packit Service fa4841
		memcpy(rdp->decrypt_key, salt, 3);
Packit Service fa4841
		memcpy(rdp->encrypt_key, salt, 3);
Packit Service fa4841
		rdp->rc4_key_len = 8;
Packit Service fa4841
	}
Packit Service fa4841
	else if (settings->EncryptionMethods == ENCRYPTION_METHOD_56BIT)
Packit Service fa4841
	{
Packit Service fa4841
		memcpy(rdp->sign_key, salt, 1);
Packit Service fa4841
		memcpy(rdp->decrypt_key, salt, 1);
Packit Service fa4841
		memcpy(rdp->encrypt_key, salt, 1);
Packit Service fa4841
		rdp->rc4_key_len = 8;
Packit Service fa4841
	}
Packit Service fa4841
	else if (settings->EncryptionMethods == ENCRYPTION_METHOD_128BIT)
Packit Service fa4841
	{
Packit Service fa4841
		rdp->rc4_key_len = 16;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	EnterCriticalSection(&rdp->critical);
Packit Service fa4841
	memcpy(rdp->decrypt_update_key, rdp->decrypt_key, 16);
Packit Service fa4841
	memcpy(rdp->encrypt_update_key, rdp->encrypt_key, 16);
Packit Service fa4841
	rdp->decrypt_use_count = 0;
Packit Service fa4841
	rdp->decrypt_checksum_use_count = 0;
Packit Service fa4841
	rdp->encrypt_use_count = 0;
Packit Service fa4841
	rdp->encrypt_checksum_use_count = 0;
Packit Service fa4841
	LeaveCriticalSection(&rdp->critical);
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL security_key_update(BYTE* key, BYTE* update_key, int key_len, rdpRdp* rdp)
Packit Service fa4841
{
Packit Service fa4841
	BYTE sha1h[WINPR_SHA1_DIGEST_LENGTH];
Packit Service fa4841
	WINPR_DIGEST_CTX* sha1 = NULL;
Packit Service fa4841
	WINPR_DIGEST_CTX* md5 = NULL;
Packit Service fa4841
	WINPR_RC4_CTX* rc4 = NULL;
Packit Service fa4841
	BYTE salt[] = { 0xD1, 0x26, 0x9E }; /* 40 bits: 3 bytes, 56 bits: 1 byte */
Packit Service fa4841
	BOOL result = FALSE;
Packit Service fa4841
	WLog_DBG(TAG, "updating RDP key");
Packit Service fa4841
Packit Service fa4841
	if (!(sha1 = winpr_Digest_New()))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Init(sha1, WINPR_MD_SHA1))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, update_key, key_len))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, pad1, sizeof(pad1)))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(sha1, key, key_len))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Final(sha1, sha1h, sizeof(sha1h)))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!(md5 = winpr_Digest_New()))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Init(md5, WINPR_MD_MD5))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, update_key, key_len))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, pad2, sizeof(pad2)))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Update(md5, sha1h, sizeof(sha1h)))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest_Final(md5, key, WINPR_MD5_DIGEST_LENGTH))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!(rc4 = winpr_RC4_New(key, key_len)))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_RC4_Update(rc4, key_len, key, key))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_40BIT)
Packit Service fa4841
		memcpy(key, salt, 3);
Packit Service fa4841
	else if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_56BIT)
Packit Service fa4841
		memcpy(key, salt, 1);
Packit Service fa4841
Packit Service fa4841
	result = TRUE;
Packit Service fa4841
out:
Packit Service fa4841
	winpr_Digest_Free(sha1);
Packit Service fa4841
	winpr_Digest_Free(md5);
Packit Service fa4841
	winpr_RC4_Free(rc4);
Packit Service fa4841
	return result;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL security_encrypt(BYTE* data, size_t length, rdpRdp* rdp)
Packit Service fa4841
{
Packit Service fa4841
	BOOL rc = FALSE;
Packit Service fa4841
	EnterCriticalSection(&rdp->critical);
Packit Service fa4841
	if (rdp->encrypt_use_count >= 4096)
Packit Service fa4841
	{
Packit Service fa4841
		if (!security_key_update(rdp->encrypt_key, rdp->encrypt_update_key, rdp->rc4_key_len, rdp))
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		winpr_RC4_Free(rdp->rc4_encrypt_key);
Packit Service fa4841
		rdp->rc4_encrypt_key = winpr_RC4_New(rdp->encrypt_key, rdp->rc4_key_len);
Packit Service fa4841
Packit Service fa4841
		if (!rdp->rc4_encrypt_key)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		rdp->encrypt_use_count = 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!winpr_RC4_Update(rdp->rc4_encrypt_key, length, data, data))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	rdp->encrypt_use_count++;
Packit Service fa4841
	rdp->encrypt_checksum_use_count++;
Packit Service fa4841
	rc = TRUE;
Packit Service fa4841
fail:
Packit Service fa4841
	LeaveCriticalSection(&rdp->critical);
Packit Service fa4841
	return rc;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL security_decrypt(BYTE* data, size_t length, rdpRdp* rdp)
Packit Service fa4841
{
Packit Service fa4841
	BOOL rc = FALSE;
Packit Service fa4841
	EnterCriticalSection(&rdp->critical);
Packit Service fa4841
	if (rdp->rc4_decrypt_key == NULL)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (rdp->decrypt_use_count >= 4096)
Packit Service fa4841
	{
Packit Service fa4841
		if (!security_key_update(rdp->decrypt_key, rdp->decrypt_update_key, rdp->rc4_key_len, rdp))
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		winpr_RC4_Free(rdp->rc4_decrypt_key);
Packit Service fa4841
		rdp->rc4_decrypt_key = winpr_RC4_New(rdp->decrypt_key, rdp->rc4_key_len);
Packit Service fa4841
Packit Service fa4841
		if (!rdp->rc4_decrypt_key)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		rdp->decrypt_use_count = 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!winpr_RC4_Update(rdp->rc4_decrypt_key, length, data, data))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	rdp->decrypt_use_count += 1;
Packit Service fa4841
	rdp->decrypt_checksum_use_count++;
Packit Service fa4841
	rc = TRUE;
Packit Service fa4841
fail:
Packit Service fa4841
	LeaveCriticalSection(&rdp->critical);
Packit Service fa4841
	return rc;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL security_hmac_signature(const BYTE* data, size_t length, BYTE* output, rdpRdp* rdp)
Packit Service fa4841
{
Packit Service fa4841
	BYTE buf[WINPR_SHA1_DIGEST_LENGTH];
Packit Service fa4841
	BYTE use_count_le[4];
Packit Service fa4841
	WINPR_HMAC_CTX* hmac;
Packit Service fa4841
	BOOL result = FALSE;
Packit Service fa4841
	EnterCriticalSection(&rdp->critical);
Packit Service fa4841
	security_UINT32_le(use_count_le, rdp->encrypt_use_count);
Packit Service fa4841
	LeaveCriticalSection(&rdp->critical);
Packit Service fa4841
Packit Service fa4841
	if (!(hmac = winpr_HMAC_New()))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_HMAC_Init(hmac, WINPR_MD_SHA1, rdp->fips_sign_key, WINPR_SHA1_DIGEST_LENGTH))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_HMAC_Update(hmac, data, length))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_HMAC_Update(hmac, use_count_le, 4))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_HMAC_Final(hmac, buf, WINPR_SHA1_DIGEST_LENGTH))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	memmove(output, buf, 8);
Packit Service fa4841
	result = TRUE;
Packit Service fa4841
out:
Packit Service fa4841
	winpr_HMAC_Free(hmac);
Packit Service fa4841
	return result;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL security_fips_encrypt(BYTE* data, size_t length, rdpRdp* rdp)
Packit Service fa4841
{
Packit Service fa4841
	BOOL rc = FALSE;
Packit Service fa4841
	size_t olen;
Packit Service fa4841
Packit Service fa4841
	EnterCriticalSection(&rdp->critical);
Packit Service fa4841
	if (!winpr_Cipher_Update(rdp->fips_encrypt, data, length, data, &olen))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	rdp->encrypt_use_count++;
Packit Service fa4841
	rc = TRUE;
Packit Service fa4841
fail:
Packit Service fa4841
	LeaveCriticalSection(&rdp->critical);
Packit Service fa4841
	return rc;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL security_fips_decrypt(BYTE* data, size_t length, rdpRdp* rdp)
Packit Service fa4841
{
Packit Service fa4841
	size_t olen;
Packit Service fa4841
Packit Service fa4841
	if (!rdp || !rdp->fips_decrypt)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Cipher_Update(rdp->fips_decrypt, data, length, data, &olen))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL security_fips_check_signature(const BYTE* data, size_t length, const BYTE* sig, rdpRdp* rdp)
Packit Service fa4841
{
Packit Service fa4841
	BYTE buf[WINPR_SHA1_DIGEST_LENGTH];
Packit Service fa4841
	BYTE use_count_le[4];
Packit Service fa4841
	WINPR_HMAC_CTX* hmac;
Packit Service fa4841
	BOOL result = FALSE;
Packit Service fa4841
	EnterCriticalSection(&rdp->critical);
Packit Service fa4841
	security_UINT32_le(use_count_le, rdp->decrypt_use_count++);
Packit Service fa4841
	LeaveCriticalSection(&rdp->critical);
Packit Service fa4841
Packit Service fa4841
	if (!(hmac = winpr_HMAC_New()))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_HMAC_Init(hmac, WINPR_MD_SHA1, rdp->fips_sign_key, WINPR_SHA1_DIGEST_LENGTH))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_HMAC_Update(hmac, data, length))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_HMAC_Update(hmac, use_count_le, 4))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_HMAC_Final(hmac, buf, WINPR_SHA1_DIGEST_LENGTH))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!memcmp(sig, buf, 8))
Packit Service fa4841
		result = TRUE;
Packit Service fa4841
Packit Service fa4841
out:
Packit Service fa4841
	winpr_HMAC_Free(hmac);
Packit Service fa4841
	return result;
Packit Service fa4841
}