summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/crypto/rc4.c
blob: e17078541c24181fde242740fe8e3b7b2ef34879 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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;
}