Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/rc4.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// Rc4.c
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
// This is a new implementation, NOT based on the existing ones in RSA32.lib.
7
// The algorithm specification is taken from "ARCFOUR Algorithm" internet
8
// draft dated July 1999, and from memory.
9
//
10
11
#include "precomp.h"
12
13
SYMCRYPT_ERROR
14
SYMCRYPT_CALL
15
SymCryptRc4Init(
16
    _Out_                   PSYMCRYPT_RC4_STATE pState,
17
    _In_reads_( cbKey )     PCBYTE              pbKey,
18
    _In_                    SIZE_T              cbKey )
19
0
{
20
0
    SIZE_T i;
21
0
    SIZE_T j;
22
0
    BYTE keyBuf[256];
23
0
    SIZE_T keyIdx;
24
25
0
    SYMCRYPT_RC4_S_TYPE T;
26
27
0
    if( cbKey > 256 || cbKey == 0 )
28
0
    {
29
0
        return SYMCRYPT_WRONG_KEY_SIZE;
30
0
    }
31
32
    //
33
    // Make a copy of the key to obey the read-once rule.
34
    //  This is a case where it looks safe to break the read-once
35
    //  rule, but it isn't. RC4 with very long keys (e.g. 256 bytes)
36
    //  is actually very vulnerable against related-key attacks.
37
    //  One obvious precaution is to limit the length of the RC4 key,
38
    //  which one of the layers above us might do.
39
    //  Allowing the key bytes to change as we read them negates
40
    //  this countermeasure.
41
    //
42
0
    memcpy( keyBuf, pbKey, cbKey );
43
44
0
    for( i=0; i<256; i++ )
45
0
    {
46
0
        pState->S[i] = (SYMCRYPT_RC4_S_TYPE) i;
47
0
    }
48
49
0
    j = 0;
50
0
    keyIdx = 0;
51
0
    for( i=0; i<256; i++ )
52
0
    {
53
54
0
        T = pState->S[i];
55
0
        j = (j + T + keyBuf[keyIdx]) & 0xff;
56
0
        pState->S[i] = pState->S[j];
57
0
        pState->S[j] = T;
58
0
        keyIdx++;
59
0
        if( keyIdx == cbKey )
60
0
        {
61
0
            keyIdx = 0;
62
0
        }
63
0
    }
64
65
    //
66
    // We store the i value already incremented for the next byte.
67
    // This seems to allow better instruction sequencing interleaving in the actual en/decrypt loop
68
    //
69
0
    pState->i = 1;
70
0
    pState->j = 0;
71
72
0
    SYMCRYPT_SET_MAGIC( pState );
73
74
0
    SymCryptWipe( keyBuf, cbKey );
75
76
0
    return SYMCRYPT_NO_ERROR;
77
0
}
78
79
80
VOID
81
SYMCRYPT_CALL
82
SymCryptRc4Crypt(
83
    _Inout_                 PSYMCRYPT_RC4_STATE pState,
84
    _In_reads_( cbData )   PCBYTE              pbSrc,
85
    _Out_writes_( cbData )  PBYTE               pbDst,
86
    _In_                    SIZE_T              cbData )
87
0
{
88
0
    SIZE_T i;
89
0
    SIZE_T j;
90
0
    SYMCRYPT_RC4_S_TYPE Ti;
91
0
    SYMCRYPT_RC4_S_TYPE Tj;
92
0
    PCBYTE pbSrcEnd = pbSrc + cbData;
93
94
0
    SYMCRYPT_CHECK_MAGIC( pState );
95
96
0
    i = pState->i;
97
0
    j = pState->j;
98
99
    //
100
    // I tried to unroll this loop 4x and use a single 32-bit operation to XOR the key
101
    // stream with the data. This actually makes the code slower by 1 c/B on a Core 2.
102
    // I suspect that that is because the instruction decoders are the bottleneck, and
103
    // a small loop can be run out of the uop queue which bypasses the instruction decoders.
104
    // A larger loop has to be decoded every time, and that slows things down.
105
    // The theoretical gain of unrolling the loop is less than 1 c/B,
106
    // and as Core 2 and derived CPUs are the most commonly used CPUs by our customers,
107
    // it is not worthwhile to persue this further.
108
    //
109
    //  - Niels Ferguson (niels) 2010-10-11
110
    //
111
112
0
    while( pbSrc < pbSrcEnd )
113
0
    {
114
        //
115
        // Our i value is already incremented
116
        //
117
0
        Ti = pState->S[i];
118
0
        j = (j + Ti ) & 0xff;
119
0
        Tj = pState->S[j];
120
0
        pState->S[i] = Tj;
121
0
        pState->S[j] = Ti;
122
0
        *pbDst = (BYTE) (*pbSrc ^ pState->S[(Ti + Tj) & 0xff]);
123
124
0
        i = (i + 1) & 0xff;
125
126
0
        pbSrc++;
127
0
        pbDst++;
128
0
    }
129
130
0
    pState->i = (BYTE) i;
131
0
    pState->j = (BYTE) j;
132
0
}
133
134
135
static const BYTE   rc4KatAnswer[ 3 ] = { 0x71, 0x46, 0x92 };
136
137
138
VOID
139
SYMCRYPT_CALL
140
SymCryptRc4Selftest(void)
141
0
{
142
0
    BYTE buf[3];
143
0
    SYMCRYPT_RC4_STATE  state;
144
145
0
    SymCryptRc4Init( &state, SymCryptTestKey32, sizeof( SymCryptTestKey32 ) );
146
147
0
    SymCryptRc4Crypt( &state, SymCryptTestMsg3, buf, sizeof( buf ) );
148
149
0
    SymCryptInjectError( buf, sizeof( buf ) );
150
151
0
    if( memcmp( buf, rc4KatAnswer, sizeof( buf )) != 0 )
152
0
    {
153
0
        SymCryptFatal( 'rc4 ' );
154
0
    }
155
156
0
}
157
158
159