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