1 /*---------------------------------------------------------------------------*
2 Project: NitroSDK - CRYPTO - demos
3 File: rc4enc.c
4
5 Copyright 2006-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2008-10-20#$
14 $Rev: 9005 $
15 $Author: okubata_ryoma $
16 *---------------------------------------------------------------------------*/
17 /*---------------------------------------------------------------------------*
18 Pseudorandom Number Generator
19 *---------------------------------------------------------------------------*/
20
21 #include <nitro.h>
22 #include <nitro/crypto.h>
23
24 #include "prng.h"
25 #include "rc4enc.h"
26
27 /*---------------------------------------------------------------------------*
28 Variable Definitions
29 *---------------------------------------------------------------------------*/
30
31 /*---------------------------------------------------------------------------*
32 Function Definitions
33 *---------------------------------------------------------------------------*/
34
35 /*---------------------------------------------------------------------------*
36 Name: InitRC4Encoder
37
38 Description: Performs initialization for encryption using the RC4 algorithm.
39
40 Arguments: context: Context structure where the RC4 key information and so on is stored
41 key: 12-byte key data
42
43 Returns: None.
44 *---------------------------------------------------------------------------*/
InitRC4Encoder(RC4EncoderContext * context,const void * key)45 void InitRC4Encoder(
46 RC4EncoderContext* context,
47 const void* key
48 )
49 {
50 MI_CpuClear8(context, sizeof(RC4EncoderContext));
51
52 // Key settings
53 MI_CpuCopy8(key, context->key, RC4ENC_USER_KEY_LENGTH);
54 }
55
56 /*---------------------------------------------------------------------------*
57 Name: EncodeRC4
58
59 Description: Performs encryption using the RC4 algorithm.
60
61 Arguments: context: Context structure where the RC4 key information and so on is stored
62 in: Input data
63 in_len: Data length
64 out: Output data
65 out_len: Size of memory secured as an output buffer
66
67 Returns: Returns the output length if successful; otherwise, returns 0.
68 *---------------------------------------------------------------------------*/
EncodeRC4(RC4EncoderContext * context,const void * in,u32 in_len,void * out,u32 out_len)69 u32 EncodeRC4(
70 RC4EncoderContext* context,
71 const void* in,
72 u32 in_len,
73 void* out,
74 u32 out_len
75 )
76 {
77 u8 digest[MATH_SHA1_DIGEST_SIZE];
78 u32 iv;
79 u8* out_ptr = (u8*)out;
80
81 if ((out_len < in_len)
82 ||
83 (out_len - in_len < RC4ENC_ADDITIONAL_SIZE))
84 {
85 // Output buffer is too small
86 return 0;
87 }
88
89 // Create random IV (Initialization Vector)
90 GetRandomBytes((u8*)(&iv), sizeof(iv));
91
92 // TODO: Converts Endian to support network byte order
93 MI_CpuCopy8(&iv, out_ptr, sizeof(iv));
94 out_ptr += sizeof(iv);
95
96 // Create the key to use this time by combining the specified key with the IV.
97 MI_CpuCopy8(&iv, &context->key[RC4ENC_USER_KEY_LENGTH], sizeof(iv));
98 CRYPTO_RC4Init(&context->rc4_context, context->key, sizeof(context->key));
99
100 // Encrypt input data
101 CRYPTO_RC4Encrypt(&context->rc4_context, in, in_len, out_ptr);
102 out_ptr += in_len;
103
104 // Calculate the message digest value of input data
105 MATH_CalcSHA1(digest, in, in_len);
106
107 // Encrypt digest value
108 CRYPTO_RC4Encrypt(&context->rc4_context, digest, MATH_SHA1_DIGEST_SIZE, out_ptr);
109 out_ptr += sizeof(digest);
110
111 return (u32)(out_ptr - out);
112 }
113
114 /*---------------------------------------------------------------------------*
115 Name: InitRC4Decoder
116
117 Description: Performs initialization for decryption using the RC4 algorithm.
118
119 Arguments: context: Context structure where the RC4 key information, etc., is stored
120 key: 12-byte key data
121
122 Returns: None.
123 *---------------------------------------------------------------------------*/
InitRC4Decoder(RC4DecoderContext * context,const void * key)124 void InitRC4Decoder(
125 RC4DecoderContext* context,
126 const void* key
127 )
128 {
129 MI_CpuClear8(context, sizeof(RC4DecoderContext));
130
131 // Key settings
132 MI_CpuCopy8(key, context->key, RC4ENC_USER_KEY_LENGTH);
133 }
134
135 /*---------------------------------------------------------------------------*
136 Name: DecodeRC4
137
138 Description: Performs decryption using the RC4 algorithm.
139 Modification check of data is also performed. This function fails if data has been altered.
140
141 Arguments: context: Context structure where the RC4 key information, etc., is stored
142 in: Input data
143 in_len: Data length
144 out: Output data
145 out_len: Size of memory secured as an ouptut buffer
146
147 Returns: Returns the output length if successful; otherwise, returns 0.
148 *---------------------------------------------------------------------------*/
DecodeRC4(RC4DecoderContext * context,const void * in,u32 in_len,void * out,u32 out_len)149 u32 DecodeRC4(
150 RC4DecoderContext* context,
151 const void* in,
152 u32 in_len,
153 void* out,
154 u32 out_len
155 )
156 {
157 u8 digest[MATH_SHA1_DIGEST_SIZE];
158 u8 decrypted_digest[MATH_SHA1_DIGEST_SIZE];
159 u32 iv;
160 u8* in_ptr = (u8*)in;
161 u32 data_len = in_len - RC4ENC_ADDITIONAL_SIZE;
162
163 if ((in_len < RC4ENC_ADDITIONAL_SIZE)
164 ||
165 (out_len < data_len))
166 {
167 // Output buffer is too small
168 return 0;
169 }
170
171 // Get IV
172 // TODO: Converts Endian to support network byte order
173 MI_CpuCopy8(in_ptr, &iv, sizeof(iv));
174 in_ptr += sizeof(iv);
175
176 // Create key to be used this time
177 MI_CpuCopy8(&iv, &context->key[RC4ENC_USER_KEY_LENGTH], sizeof(iv));
178 CRYPTO_RC4Init(&context->rc4_context, context->key, sizeof(context->key));
179
180 // Decrypt input data
181 CRYPTO_RC4Decrypt(&context->rc4_context, in_ptr, data_len, out);
182 in_ptr += data_len;
183
184 // Calculate the message digest value of decrypted data
185 MATH_CalcSHA1(digest, out, data_len);
186
187 // Decrypt the digest value
188 CRYPTO_RC4Decrypt(&context->rc4_context, in_ptr, MATH_SHA1_DIGEST_SIZE, decrypted_digest);
189 in_ptr += data_len;
190
191 // Verifies that the digest value is correct
192 {
193 int i;
194 for (i = 0; i < MATH_SHA1_DIGEST_SIZE; i++)
195 {
196 if (digest[i] != decrypted_digest[i])
197 {
198 // Verification failed
199 return 0;
200 }
201 }
202 }
203
204 return data_len;
205 }
206
207
208 /*---------------------------------------------------------------------------*
209 End of file
210 *---------------------------------------------------------------------------*/
211