• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/http/des.h"
6 
7 #if defined(USE_NSS)
8 #include <nss.h>
9 #include <pk11pub.h>
10 #elif defined(OS_MACOSX)
11 #include <CommonCrypto/CommonCryptor.h>
12 #elif defined(OS_WIN)
13 #include <windows.h>
14 #include <wincrypt.h>
15 #endif
16 
17 #include "base/logging.h"
18 #if defined(USE_NSS)
19 #include "base/nss_util.h"
20 #endif
21 
22 // The Mac and Windows (CryptoAPI) versions of DESEncrypt are our own code.
23 // DESSetKeyParity, DESMakeKey, and the Linux (NSS) version of DESEncrypt are
24 // based on mozilla/security/manager/ssl/src/nsNTLMAuthModule.cpp,
25 // CVS rev. 1.14.
26 
27 /* ***** BEGIN LICENSE BLOCK *****
28  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
29  *
30  * The contents of this file are subject to the Mozilla Public License Version
31  * 1.1 (the "License"); you may not use this file except in compliance with
32  * the License. You may obtain a copy of the License at
33  * http://www.mozilla.org/MPL/
34  *
35  * Software distributed under the License is distributed on an "AS IS" basis,
36  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
37  * for the specific language governing rights and limitations under the
38  * License.
39  *
40  * The Original Code is Mozilla.
41  *
42  * The Initial Developer of the Original Code is IBM Corporation.
43  * Portions created by IBM Corporation are Copyright (C) 2003
44  * IBM Corporation. All Rights Reserved.
45  *
46  * Contributor(s):
47  *   Darin Fisher <darin@meer.net>
48  *
49  * Alternatively, the contents of this file may be used under the terms of
50  * either the GNU General Public License Version 2 or later (the "GPL"), or
51  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
52  * in which case the provisions of the GPL or the LGPL are applicable instead
53  * of those above. If you wish to allow use of your version of this file only
54  * under the terms of either the GPL or the LGPL, and not to allow others to
55  * use your version of this file under the terms of the MPL, indicate your
56  * decision by deleting the provisions above and replace them with the notice
57  * and other provisions required by the GPL or the LGPL. If you do not delete
58  * the provisions above, a recipient may use your version of this file under
59  * the terms of any one of the MPL, the GPL or the LGPL.
60  *
61  * ***** END LICENSE BLOCK ***** */
62 
63 // Set odd parity bit (in least significant bit position).
DESSetKeyParity(uint8 x)64 static uint8 DESSetKeyParity(uint8 x) {
65   if ((((x >> 7) ^ (x >> 6) ^ (x >> 5) ^
66         (x >> 4) ^ (x >> 3) ^ (x >> 2) ^
67         (x >> 1)) & 0x01) == 0) {
68     x |= 0x01;
69   } else {
70     x &= 0xfe;
71   }
72   return x;
73 }
74 
75 namespace net {
76 
DESMakeKey(const uint8 * raw,uint8 * key)77 void DESMakeKey(const uint8* raw, uint8* key) {
78   key[0] = DESSetKeyParity(raw[0]);
79   key[1] = DESSetKeyParity((raw[0] << 7) | (raw[1] >> 1));
80   key[2] = DESSetKeyParity((raw[1] << 6) | (raw[2] >> 2));
81   key[3] = DESSetKeyParity((raw[2] << 5) | (raw[3] >> 3));
82   key[4] = DESSetKeyParity((raw[3] << 4) | (raw[4] >> 4));
83   key[5] = DESSetKeyParity((raw[4] << 3) | (raw[5] >> 5));
84   key[6] = DESSetKeyParity((raw[5] << 2) | (raw[6] >> 6));
85   key[7] = DESSetKeyParity((raw[6] << 1));
86 }
87 
88 #if defined(USE_NSS)
89 
DESEncrypt(const uint8 * key,const uint8 * src,uint8 * hash)90 void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) {
91   CK_MECHANISM_TYPE cipher_mech = CKM_DES_ECB;
92   PK11SlotInfo* slot = NULL;
93   PK11SymKey* symkey = NULL;
94   PK11Context* ctxt = NULL;
95   SECItem key_item;
96   SECItem* param = NULL;
97   SECStatus rv;
98   unsigned int n;
99 
100   base::EnsureNSSInit();
101 
102   slot = PK11_GetBestSlot(cipher_mech, NULL);
103   if (!slot)
104     goto done;
105 
106   key_item.data = const_cast<uint8*>(key);
107   key_item.len = 8;
108   symkey = PK11_ImportSymKey(slot, cipher_mech,
109                              PK11_OriginUnwrap, CKA_ENCRYPT,
110                              &key_item, NULL);
111   if (!symkey)
112     goto done;
113 
114   // No initialization vector required.
115   param = PK11_ParamFromIV(cipher_mech, NULL);
116   if (!param)
117     goto done;
118 
119   ctxt = PK11_CreateContextBySymKey(cipher_mech, CKA_ENCRYPT,
120                                     symkey, param);
121   if (!ctxt)
122     goto done;
123 
124   rv = PK11_CipherOp(ctxt, hash, reinterpret_cast<int*>(&n), 8,
125                      const_cast<uint8*>(src), 8);
126   if (rv != SECSuccess)
127     goto done;
128 
129   // TODO(wtc): Should this be PK11_Finalize?
130   rv = PK11_DigestFinal(ctxt, hash+8, &n, 0);
131   if (rv != SECSuccess)
132     goto done;
133 
134  done:
135   if (ctxt)
136     PK11_DestroyContext(ctxt, PR_TRUE);
137   if (symkey)
138     PK11_FreeSymKey(symkey);
139   if (param)
140     SECITEM_FreeItem(param, PR_TRUE);
141   if (slot)
142     PK11_FreeSlot(slot);
143 }
144 
145 #elif defined(OS_MACOSX)
146 
DESEncrypt(const uint8 * key,const uint8 * src,uint8 * hash)147 void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) {
148   CCCryptorStatus status;
149   size_t data_out_moved = 0;
150   status = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode,
151                    key, 8, NULL, src, 8, hash, 8, &data_out_moved);
152   DCHECK(status == kCCSuccess);
153   DCHECK(data_out_moved == 8);
154 }
155 
156 #elif defined(OS_WIN)
157 
DESEncrypt(const uint8 * key,const uint8 * src,uint8 * hash)158 void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) {
159   HCRYPTPROV provider;
160   HCRYPTKEY hkey = NULL;
161 
162   if (!CryptAcquireContext(&provider, NULL, NULL,
163                            PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
164     provider = NULL;
165     goto done;
166   }
167 
168   // Import the DES key.
169   // This code doesn't work on Win2k because PLAINTEXTKEYBLOB is not supported
170   // on Windows 2000.  PLAINTEXTKEYBLOB allows the import of an unencrypted
171   // key.  For Win2k support, a cubmbersome exponent-of-one key procedure must
172   // be used:
173   //     http://support.microsoft.com/kb/228786/en-us
174 
175   struct KeyBlob {
176     BLOBHEADER header;
177     DWORD key_size;
178     BYTE key_data[8];
179   };
180   KeyBlob key_blob;
181   key_blob.header.bType = PLAINTEXTKEYBLOB;
182   key_blob.header.bVersion = CUR_BLOB_VERSION;
183   key_blob.header.reserved = 0;
184   key_blob.header.aiKeyAlg = CALG_DES;
185   key_blob.key_size = 8;  // 64 bits
186   memcpy(key_blob.key_data, key, 8);
187 
188   if (!CryptImportKey(provider, reinterpret_cast<BYTE*>(&key_blob),
189                       sizeof(key_blob), 0, 0, &hkey)) {
190     hkey = NULL;
191     goto done;
192   }
193 
194   // Destroy the copy of the key.
195   SecureZeroMemory(key_blob.key_data, sizeof(key_blob.key_data));
196 
197   // No initialization vector required.
198   DWORD cipher_mode = CRYPT_MODE_ECB;
199   if (!CryptSetKeyParam(hkey, KP_MODE,
200                         reinterpret_cast<BYTE*>(&cipher_mode), 0))
201     goto done;
202 
203   // CryptoAPI requires us to copy the plaintext to the output buffer first.
204   CopyMemory(hash, src, 8);
205   // Pass a 'Final' of FALSE, otherwise CryptEncrypt appends one additional
206   // block of padding to the data.
207   DWORD hash_len = 8;
208   if (!CryptEncrypt(hkey, NULL, FALSE, 0, hash, &hash_len, 8))
209     goto done;
210 
211  done:
212   if (hkey)
213     CryptDestroyKey(hkey);
214   if (provider)
215     CryptReleaseContext(provider, 0);
216 }
217 
218 #endif
219 
220 }  // namespace net
221