/* * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #if defined(MACINTOSH) #include #endif #include "DES.h" #define kVersion1 1 #define kVersion2 2 void DES (long* keysArrayPtr, long Count, char * encryptData,short mode); #define klonghiBit 0x80000000L #define kwordhiBit 0x8000 #define klongloBit 0x00000001L #define kbit0 0x00000000L #define klowWord 0x0000FFFFL #define khiBit 0x00000020L #define kwordSize 16 #define kkeyArraySize 128 /* bytes for 16 keys */ #define klowKeySize 4 /* bytes in half the key size */ #define knumKeys 16 /* # keys in key array */ #define kkeySize 8 /* bytes per key */ #define kDecrypt 1 #define kEncrypt 0 typedef struct doubleLong { unsigned short bits49to64; unsigned short bits17to32; unsigned short bits33to48; unsigned short bits1to16; } doubleLong; typedef char byte; /* Internal function prototypes */ #if defined(__cplusplus) extern "C" { #endif void Permute(EncryptBlk *aBlkPTr, long* aKeyPtr); long RotateExtended(unsigned short *theWord, unsigned long resultLo); void Extract(doubleLong *ExtractData, unsigned long *resultLow, unsigned long *resultHigh); void InitialPermutation(EncryptBlk *sourceBlkPTr,EncryptBlk *resultBlkPTr ); long FRK(unsigned long theData,unsigned long keyHi,unsigned long keyLo); #if defined(__cplusplus) } #endif /* -------------------------------------------------------------------- */ /* Macros */ /* -------------------------------------------------------------------- */ /* Most of these macros emulate the 68K instruction set used in the original assembly language version of this code.*/ #define GetBit(val,Reg) gTestVal = val; gTestVal = gTestVal % khiBit; gTemp = klongloBit; if (gTestVal != 0L) gTemp = gTemp << gTestVal; #define BitClear(val,Reg) GetBit(val,Reg); Reg = Reg & (~gTemp); #define BitSet(bit,Reg) GetBit(bit,Reg) Reg = Reg | gTemp; #define BitTest(val, Reg) GetBit(val,Reg); gTestVal = gTemp & Reg; #define BNE(label) if (gTestVal != 0) goto label; #define BEQ(label) if (gTestVal == 0) goto label; #define BRA(label) goto label; #define Compare(val,reg) gTestVal = val - reg; #define EXchange(reg1,reg2) gTemp = reg1;reg1 = reg2; reg2 = gTemp; #define LSLword(Reg,amount) gTestVal = kwordhiBit & Reg; ;Reg = Reg << amount; #define LSRword(Reg,amount) BitTest(1,Reg); Reg = Reg >> amount; #define LSL(Reg,amount) gTestVal = klonghiBit & Reg; Reg = Reg << amount; #define LSR(Reg,amount) gTestVal = klongloBit & Reg ; Reg = Reg >> amount; #define ROLeftLong(Reg) LSL(Reg,1); if (gTestVal != 0) Reg = Reg | klongloBit; #define RORightLong(Reg) LSR(Reg,1); if (gTestVal != 0) Reg = Reg | klonghiBit; #define ROXLeftLong(Reg) Reg = Reg << 1;if (xVal != 0) Reg = Reg | klongloBit; #define ROXRightLong(Reg) Reg = Reg >> 1; if (xVal != 0) Reg = Reg | klonghiBit; #define RORightLong4(Reg) xVal = Reg & 0x0000000FL; xVal = xVal << 28; Reg = Reg >> 4; if (xVal != 0) Reg = Reg | xVal; #define TheLastKey(ArrayPtr) (unsigned long *) ((char *) ArrayPtr + (kkeyArraySize - klowKeySize )); /* -------------------------------------------------------------------- */ /* Permute tables for permutation */ /* -------------------------------------------------------------------- */ const byte N_PC1Tbl[58] = { /* ks permutation iteration = 1 */ 7, 15, 23, 31, 39, 47, 55, 63, 6, 14, 22, 30, 38, 46, 54, 62, 5, 13, 21, 29, 37, 45, 53, 61, 4, 12, 20, 28, -1, /* swap */ 1, 9, 17, 25, 33, 41, 49, 57, 2, 10, 18, 26, 34, 42, 50, 58, 3, 11, 19, 27, 35, 43, 51, 59, 36, 44, 52, 60, -2 /* end-of-table */ }; const byte N_PC2Tbl[50] = { /* ks permutation iteration = 1 */ 50, 47, 53, 40, 63, 59, 61, 36, 49, 58, 43, 54, 41, 45, 52, 60, -1, /* swap */ 38, 56, 48, 57, 37, 44, 51, 62, 19, 8, 29, 23, 13, 5, 30, 20, 9, 15, 27, 12, 16, 11, 21, 4, 26, 7, 14, 18, 10, 24, 31, 28, -2 /* end-of-table */ }; const byte N_IPInvTbl[66] = { 24, 56, 16, 48, 8, 40, 0, 32, 25, 57, 17, 49, 9, 41, 1, 33, 26, 58, 18, 50, 10, 42, 2, 34, 27, 59, 19, 51, 11, 43, 3, 35, -1, /* swap */ 28, 60, 20, 52, 12, 44, 4, 36, 29, 61, 21, 53, 13, 45, 5, 37, 30, 62, 22, 54, 14, 46, 6, 38, 31, 63, 23, 55, 15, 47, 7, 39, -2 /* end-of-table */ }; const byte N_PTbl[33] = { 16, 25, 12, 11, 3, 20, 4, 15, 31, 17, 9, 6, 27, 14, 1, 22, 30, 24, 8, 18, 0, 5, 29, 23, 13, 19, 2, 26, 10, 21, 28, 7, -2 /* end-of-table */ }; /* -------------------------------------------------------------------- */ /* SBox Tables for DES C code */ /* -------------------------------------------------------------------- */ const byte N_SBoxes[512] = { /* S8 */ 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4, 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13, 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11, // S7 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6, 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7, 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12, // S6 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5, 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8, 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13, // S5 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1, 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13, 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3, // S4 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9, 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14, // S3 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12, // S2 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2, 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9, // S1 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13, }; void Permute(EncryptBlk *aBlkPTr, long* aKeyPtr) { register char bitPos; char* ArrayPtr; register unsigned long keyLo; register unsigned long keyHi; register unsigned long loBits; register unsigned long hiBits; register unsigned long gTestVal; register unsigned long gTemp; register unsigned long arrayByte; bitPos = 0; hiBits = 0; loBits = 0; keyLo = aBlkPTr->keyLo; keyHi = aBlkPTr->keyHi; ArrayPtr = (char*) aKeyPtr; bitPos = *ArrayPtr ++; /* get source bit */ Loop: arrayByte = bitPos; ROLeftLong(hiBits); BitTest(5, arrayByte); BEQ(jump20); BitClear(5,arrayByte); BitTest(arrayByte,keyLo); BNE(jump30); BRA(jump40); jump20: BitTest(arrayByte,keyHi); BEQ(jump40); jump30: BitSet(kbit0,hiBits); jump40: bitPos = *ArrayPtr++; if (bitPos >= 0) goto Loop; EXchange(hiBits,loBits); if ( bitPos != -1 ) goto jump50; bitPos = *ArrayPtr++; goto Loop; jump50: aBlkPTr->keyLo = loBits; /* low bits */ aBlkPTr->keyHi = hiBits; } /* -------------------------------------------------------------------- */ /* KeyScheduler */ /* -------------------------------------------------------------------- */ void KeySched(const EncryptBlk *Key, long* keysArrayPtr, short version) { EncryptBlk permuteKey; unsigned long *keyPtr; register unsigned long keyLo; register unsigned long keyHi; register short shiftSchedule; register unsigned long gTestVal; permuteKey.keyLo = Key->keyHi; permuteKey.keyHi = Key->keyLo; if (version > kVersion1 ) /* PPC and AppleShare 1.0 use version 1 (see RAndrews comment)*/ { LSL(permuteKey.keyLo,1); LSL(permuteKey.keyHi,1); } keyPtr = (unsigned long *)keysArrayPtr; Permute(&permuteKey, (long *)&N_PC1Tbl); keyLo = permuteKey.keyLo; keyHi = permuteKey.keyHi; LSL(keyLo,4); LSL(keyHi,4); shiftSchedule = 0xC081; jump5: LSLword(shiftSchedule,1); BNE(jump20); LSL(keyHi,1); BEQ(jump10); keyHi = keyHi | 16; jump10: LSL(keyLo,1) BEQ(jump20); keyLo = keyLo | 16; jump20: LSL(keyHi,1) BEQ(jump30); keyHi = keyHi | 16; jump30: LSL(keyLo,1) BEQ(jump40); keyLo = keyLo | 16; jump40: permuteKey.keyLo = keyHi; permuteKey.keyHi = keyLo; Permute((EncryptBlk *) &permuteKey,(long*)&N_PC2Tbl); *keyPtr = permuteKey.keyHi; keyPtr ++ ; *keyPtr = permuteKey.keyLo; keyPtr ++ ; if (shiftSchedule != 0) goto jump5; } /* -------------------------------------------------------------------- */ /* Encode and Decode + support routines */ /* -------------------------------------------------------------------- */ long RotateExtended(unsigned short *theWord, unsigned long resultLo) { register unsigned long xVal = 0; register unsigned short tempPiece; tempPiece = *theWord; xVal = tempPiece & kwordhiBit; tempPiece = tempPiece << 1; *theWord = tempPiece; ROXLeftLong(resultLo); xVal = resultLo & klonghiBit; ROXLeftLong(resultLo); return resultLo; } void Extract(doubleLong *ExtractData, unsigned long *resultLow, unsigned long *resultHigh) { short i; unsigned long resultLo; unsigned long resultHi; unsigned long gTemp; resultLo = *resultLow; resultHi = *resultHigh; for (i = kkeySize; i > 0; i--) { resultLo = RotateExtended(&ExtractData->bits49to64, resultLo); resultLo = RotateExtended(&ExtractData->bits17to32, resultLo); resultLo = RotateExtended(&ExtractData->bits33to48, resultLo); resultLo = RotateExtended(&ExtractData->bits1to16, resultLo); EXchange(resultLo,resultHi); } *resultLow = resultLo; *resultHigh = resultHi; } void InitialPermutation(EncryptBlk *sourceBlkPTr,EncryptBlk *resultBlkPTr ) { doubleLong dataToEncrypt; unsigned long resultLow = 0; unsigned long resultHi = 0; register unsigned long gTestVal = 0; dataToEncrypt.bits49to64 = sourceBlkPTr->keyLo & klowWord; dataToEncrypt.bits33to48 = sourceBlkPTr->keyHi & klowWord; dataToEncrypt.bits17to32 = sourceBlkPTr->keyLo >> kwordSize; dataToEncrypt.bits1to16 = sourceBlkPTr->keyHi >> kwordSize; Extract(&dataToEncrypt, &resultLow, &resultHi); RORightLong(resultLow) RORightLong(resultHi) Extract(&dataToEncrypt, &resultLow, &resultHi); resultBlkPTr->keyLo = resultLow; resultBlkPTr->keyHi = resultHi; } long FRK(unsigned long theData,unsigned long keyHi,unsigned long keyLo) { register unsigned long gTestVal = 0; register unsigned long xVal = 0; register unsigned short tempData = 0; register unsigned long result = 0; char tableVal; EncryptBlk encryptBlock; short counter; short count; short offset = 0; ROLeftLong(theData); for ( counter = kkeySize; counter > 0 ; ) { tempData = theData; tempData = tempData ^ keyLo; tempData = tempData & 0x3F; /* mask off all but lowest 6 bits */ tableVal = N_SBoxes[tempData + offset]; result = result | tableVal; RORightLong4(result); if (--counter == 0) break; RORightLong4(theData); offset = offset + 64; for (count = 6; count > 0; count --) { /*LRORightLong(keyHi);*/ xVal = keyHi & klongloBit; keyHi = keyHi >> 1; ROXRightLong(keyLo); } } encryptBlock.keyHi = result; encryptBlock.keyLo = keyHi; Permute(&encryptBlock, (long*)&N_PTbl ); return encryptBlock.keyLo; } void Encode (long* keysArrayPtr, long Count, char * encryptData) { DES(keysArrayPtr,Count,encryptData,kEncrypt); } void Decode (long* keysArrayPtr, long Count, char * encryptData) { DES(keysArrayPtr,Count,encryptData,kDecrypt); } void DES (long* keysArrayPtr, long Count, char * encryptData,short mode) { EncryptBlk *EncryptDataPtr; EncryptBlk resultData; EncryptBlk *ReturnData; short swapCount; unsigned long fResult; unsigned long gTemp; unsigned long keyHi; unsigned long keyLo; unsigned long *keyPtr; EncryptDataPtr = (EncryptBlk *) encryptData; ReturnData = EncryptDataPtr; for ( ;Count > 0; Count -= kkeySize) { InitialPermutation(EncryptDataPtr, &resultData ); if (mode == kEncrypt) keyPtr = (unsigned long*)keysArrayPtr; else /* must be decrypt */ keyPtr = TheLastKey(keysArrayPtr); /* start at last key in array */ for (swapCount = knumKeys; swapCount != 0; swapCount--) { if (mode == kEncrypt) { keyHi = *keyPtr++; keyLo = *keyPtr++; } else /* must be decrypt */ { keyLo = *keyPtr--; keyHi = *keyPtr--; } fResult = FRK(resultData.keyLo,keyHi,keyLo); resultData.keyHi = resultData.keyHi ^ fResult; if (swapCount > 1) /* EXchange is multi-line macro and requires {}*/ { EXchange(resultData.keyHi,resultData.keyLo); } } EXchange(resultData.keyHi,resultData.keyLo); Permute(&resultData,(long*)&N_IPInvTbl); EncryptDataPtr = (EncryptBlk *) (((char*) EncryptDataPtr) + kkeySize); } ReturnData->keyLo = resultData.keyLo; ReturnData->keyHi = resultData.keyHi; }