[winpr,crypto] add internal rc4 replacement

RDP relies on RC4 for some operations, so we need these to successfully
log on to windows machines. This is a replacement for use with SSL
libraries that have already deprecated these.
This commit is contained in:
Armin Novak 2023-05-17 10:07:08 +02:00 committed by akallabeth
parent 06bd759c64
commit 0c7330720f
6 changed files with 169 additions and 27 deletions

View File

@ -64,6 +64,7 @@ option(WITH_DEBUG_SYMBOLS "Pack debug symbols to installer" OFF)
option(WITH_NATIVE_SSPI "Use native SSPI modules" ${NATIVE_SSPI})
option(WITH_SMARTCARD_INSPECT "Enable SmartCard API Inspector" OFF)
option(WITH_DEBUG_MUTEX "Print mutex debug messages" ${DEFAULT_DEBUG_OPTION})
option(WITH_INTERNAL_RC4 "Use compiled in rc4 functions instead of OpenSSL/MBedTLS" OFF)
option(WITH_INTERNAL_MD4 "Use compiled in md4 hash functions instead of OpenSSL/MBedTLS" OFF)
option(WITH_INTERNAL_MD5 "Use compiled in md5 hash functions instead of OpenSSL/MBedTLS" OFF)
option(WITH_UNICODE_BUILTIN "Use built-in Unicode conversion (don't use system-provided libraries)" OFF)

View File

@ -27,6 +27,7 @@
#cmakedefine WITH_EVENTFD_READ_WRITE
#cmakedefine WITH_NATIVE_SSPI
#cmakedefine WITH_INTERNAL_RC4
#cmakedefine WITH_INTERNAL_MD4
#cmakedefine WITH_INTERNAL_MD5

View File

@ -23,6 +23,10 @@ set(SRCS
crypto.c
crypto.h
)
if (WITH_INTERNAL_RC4)
list(APPEND SRCS rc4.c rc4.h)
endif()
if (WITH_INTERNAL_MD4)
list(APPEND SRCS md4.c md4.h)
endif()

View File

@ -25,6 +25,10 @@
#include "../log.h"
#define TAG WINPR_TAG("crypto.cipher")
#if defined(WITH_INTERNAL_RC4)
#include "rc4.h"
#endif
#ifdef WITH_OPENSSL
#include <openssl/aes.h>
#include <openssl/rc4.h>
@ -46,23 +50,21 @@
struct winpr_rc4_ctx_private_st
{
union
{
#if defined(WITH_INTERNAL_RC4)
winpr_int_RC4_CTX* ictx;
#else
#if defined(WITH_OPENSSL)
EVP_CIPHER_CTX* ctx;
EVP_CIPHER_CTX* ctx;
#endif
#if defined(WITH_MBEDTLS) && defined(MBEDTLS_ARC4_C)
mbedtls_arc4_context mctx;
mbedtls_arc4_context* mctx;
#endif
#endif
} u;
};
static WINPR_RC4_CTX* winpr_RC4_New_Internal(const BYTE* key, size_t keylen, BOOL override_fips)
{
WINPR_RC4_CTX* ctx = NULL;
#if defined(WITH_OPENSSL)
const EVP_CIPHER* evp = NULL;
#endif
if (!key || (keylen == 0))
return NULL;
@ -71,13 +73,19 @@ static WINPR_RC4_CTX* winpr_RC4_New_Internal(const BYTE* key, size_t keylen, BOO
if (!ctx)
return NULL;
#if defined(WITH_OPENSSL)
#if defined(WITH_INTERNAL_RC4)
WINPR_UNUSED(override_fips);
ctx->ictx = winpr_int_rc4_new(key, keylen);
if (!ctx->ictx)
goto fail;
#elif defined(WITH_OPENSSL)
const EVP_CIPHER* evp = NULL;
if (keylen > INT_MAX)
goto fail;
ctx->u.ctx = EVP_CIPHER_CTX_new();
if (!ctx->u.ctx)
ctx->ctx = EVP_CIPHER_CTX_new();
if (!ctx->ctx)
goto fail;
evp = EVP_rc4();
@ -85,27 +93,29 @@ static WINPR_RC4_CTX* winpr_RC4_New_Internal(const BYTE* key, size_t keylen, BOO
if (!evp)
goto fail;
EVP_CIPHER_CTX_init(ctx->u.ctx);
if (EVP_EncryptInit_ex(ctx->u.ctx, evp, NULL, NULL, NULL) != 1)
EVP_CIPHER_CTX_init(ctx->ctx);
if (EVP_EncryptInit_ex(ctx->ctx, evp, NULL, NULL, NULL) != 1)
goto fail;
/* EVP_CIPH_FLAG_NON_FIPS_ALLOW does not exist before openssl 1.0.1 */
#if !(OPENSSL_VERSION_NUMBER < 0x10001000L)
if (override_fips == TRUE)
EVP_CIPHER_CTX_set_flags(ctx->u.ctx, EVP_CIPH_FLAG_NON_FIPS_ALLOW);
EVP_CIPHER_CTX_set_flags(ctx->ctx, EVP_CIPH_FLAG_NON_FIPS_ALLOW);
#endif
EVP_CIPHER_CTX_set_key_length(ctx->u.ctx, (int)keylen);
if (EVP_EncryptInit_ex(ctx->u.ctx, NULL, NULL, key, NULL) != 1)
EVP_CIPHER_CTX_set_key_length(ctx->ctx, (int)keylen);
if (EVP_EncryptInit_ex(ctx->ctx, NULL, NULL, key, NULL) != 1)
goto fail;
#elif defined(WITH_MBEDTLS) && defined(MBEDTLS_ARC4_C)
ctx->u.mctx = calloc(1, sizeof(mbedtls_arc4_context)) if (!ctx->u.mctx) goto fail;
ctx->mctx = calloc(1, sizeof(mbedtls_arc4_context));
if (!ctx->mctx)
goto fail;
mbedtls_arc4_init(ctx->u.mctx);
mbedtls_arc4_setup(ctx->u.mctx, key, (unsigned int)keylen);
mbedtls_arc4_init(ctx->mctx);
mbedtls_arc4_setup(ctx->mctx, key, (unsigned int)keylen);
#endif
return ctx;
@ -127,18 +137,23 @@ WINPR_RC4_CTX* winpr_RC4_New(const BYTE* key, size_t keylen)
BOOL winpr_RC4_Update(WINPR_RC4_CTX* ctx, size_t length, const BYTE* input, BYTE* output)
{
WINPR_ASSERT(ctx);
#if defined(WITH_OPENSSL)
WINPR_ASSERT(ctx->u.ctx);
#if defined(WITH_INTERNAL_RC4)
return winpr_int_rc4_update(ctx->ictx, length, input, output);
#elif defined(WITH_OPENSSL)
WINPR_ASSERT(ctx->ctx);
int outputLength;
if (length > INT_MAX)
return FALSE;
EVP_CipherUpdate(ctx->u.ctx, output, &outputLength, input, (int)length);
WINPR_ASSERT(ctx);
if (EVP_CipherUpdate(ctx->ctx, output, &outputLength, input, (int)length) != 1)
return FALSE;
return TRUE;
#elif defined(WITH_MBEDTLS) && defined(MBEDTLS_ARC4_C)
WINPR_ASSERT(ctx->u.mctx);
if (mbedtls_arc4_crypt(ctx->u.mctx, length, input, output) == 0)
WINPR_ASSERT(ctx->mctx);
if (mbedtls_arc4_crypt(ctx->mctx, length, input, output) == 0)
return TRUE;
#endif
@ -150,10 +165,12 @@ void winpr_RC4_Free(WINPR_RC4_CTX* ctx)
if (!ctx)
return;
#if defined(WITH_OPENSSL)
EVP_CIPHER_CTX_free(ctx->u.ctx);
#if defined(WITH_INTERNAL_RC4)
winpr_int_rc4_free(ctx->ictx);
#elif defined(WITH_OPENSSL)
EVP_CIPHER_CTX_free(ctx->ctx);
#elif defined(WITH_MBEDTLS) && defined(MBEDTLS_ARC4_C)
mbedtls_arc4_free(ctx->u.mctx);
mbedtls_arc4_free(ctx->mctx);
#endif
free(ctx);
}

View File

@ -0,0 +1,88 @@
/**
* WinPR: Windows Portable Runtime
* RC4 implementation for RDP
*
* Copyright 2023 Armin Novak <anovak@thincast.com>
* Copyright 2023 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/assert.h>
#include "rc4.h"
#define CTX_SIZE 256
struct winpr_int_rc4_ctx
{
size_t i;
size_t j;
BYTE s[CTX_SIZE];
BYTE t[CTX_SIZE];
};
static void swap(BYTE* p1, BYTE* p2)
{
BYTE t = *p1;
*p1 = *p2;
*p2 = t;
}
winpr_int_RC4_CTX* winpr_int_rc4_new(const BYTE* key, size_t keylength)
{
winpr_int_RC4_CTX* ctx = calloc(1, sizeof(winpr_int_RC4_CTX));
if (!ctx)
return NULL;
for (size_t i = 0; i < CTX_SIZE; i++)
{
ctx->s[i] = i;
ctx->t[i] = key[i % keylength];
}
size_t j = 0;
for (size_t i = 0; i < CTX_SIZE; i++)
{
j = (j + ctx->s[i] + ctx->t[i]) % CTX_SIZE;
swap(&ctx->s[i], &ctx->s[j]);
}
return ctx;
}
void winpr_int_rc4_free(winpr_int_RC4_CTX* ctx)
{
free(ctx);
}
BOOL winpr_int_rc4_update(winpr_int_RC4_CTX* ctx, size_t length, const BYTE* input, BYTE* output)
{
WINPR_ASSERT(ctx);
UINT32 t1 = ctx->i;
UINT32 t2 = ctx->j;
for (size_t i = 0; i < length; i++)
{
t1 = (t1 + 1) % CTX_SIZE;
t2 = (t2 + ctx->s[t1]) % CTX_SIZE;
swap(&ctx->s[t1], &ctx->s[t2]);
const size_t idx = ((size_t)ctx->s[t1] + ctx->s[t2]) % CTX_SIZE;
const BYTE val = ctx->s[idx];
const BYTE out = *input++ ^ val;
*output++ = out;
}
ctx->i = t1;
ctx->j = t2;
return TRUE;
}

View File

@ -0,0 +1,31 @@
/**
* WinPR: Windows Portable Runtime
* RC4 implementation for RDP
*
* Copyright 2023 Armin Novak <anovak@thincast.com>
* Copyright 2023 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_RC4_H
#define WINPR_RC4_H
#include <winpr/wtypes.h>
typedef struct winpr_int_rc4_ctx winpr_int_RC4_CTX;
winpr_int_RC4_CTX* winpr_int_rc4_new(const BYTE* key, size_t keylength);
BOOL winpr_int_rc4_update(winpr_int_RC4_CTX* ctx, size_t length, const BYTE* input, BYTE* output);
void winpr_int_rc4_free(winpr_int_RC4_CTX* ctx);
#endif