A new version of CryptographyCiphers was added to project The Inbox:
http://source.squeak.org/inbox/CryptographyCiphers-tpr.21.mcz ==================== Summary ==================== Name: CryptographyCiphers-tpr.21 Author: tpr Time: 28 May 2020, 4:00:52.885539 pm UUID: c7be74a1-dca8-4c50-8d6c-8747238dd0f8 Ancestors: CryptographyCiphers-rww.20 Fix Blowfish to handle strings other than 8 chars long. ==================== Snapshot ==================== SystemOrganization addCategory: #'CryptographyCiphers-ARC2'! SystemOrganization addCategory: #'CryptographyCiphers-Blowfish'! SystemOrganization addCategory: #'CryptographyCiphers-DES'! SystemOrganization addCategory: #'CryptographyCiphers-RC4'! SystemOrganization addCategory: #'CryptographyCiphers-Rijndael'! Object subclass: #ARC4 instanceVariableNames: 'sbox i j' classVariableNames: '' poolDictionaries: '' category: 'CryptographyCiphers-RC4'! ----- Method: ARC4>>decrypt: (in category 'accessing') ----- decrypt: aByteArray ^ self encrypt: aByteArray! ----- Method: ARC4>>encrypt: (in category 'accessing') ----- encrypt: aByteArray | newBytes | newBytes := aByteArray copy. 1 to: aByteArray size do: [ :each | newBytes at: each put: ((aByteArray at: each) bitXor: self next)]. ^ newBytes! ----- Method: ARC4>>key: (in category 'accessing') ----- key: aByteArray | k other | sbox := (0 to: 255) asByteArray. k := (0 to: 255) collect: [ :each | aByteArray at: each \\ aByteArray size + 1]. other := 0. 1 to: 256 do: [ :each | other := other + (sbox at: each) + (k at: each) \\ 256. sbox swap: each with: other+1]. i := j := 0! ----- Method: ARC4>>next (in category 'accessing') ----- next | t | i := i + 1 \\ 256. j := j + (sbox at: i+1) \\ 256. sbox swap: i+1 with: j+1. t := (sbox at: i+1) + (sbox at: j+1) \\ 256. ^ sbox at: t+1! Object subclass: #BlowfishProfiling instanceVariableNames: 'keys clear encrypted' classVariableNames: '' poolDictionaries: '' category: 'CryptographyCiphers-Blowfish'! ----- Method: BlowfishProfiling class>>longTest (in category 'as yet unclassified') ----- longTest ! ----- Method: BlowfishProfiling>>initialize (in category 'as yet unclassified') ----- initialize super initialize. self initializeClear; initializeEncrypted; initializeKeys! ----- Method: BlowfishProfiling>>initializeClear (in category 'as yet unclassified') ----- initializeClear | tmpClear | clear := OrderedCollection new. tmpClear := #('0000000000000000' 'FFFFFFFFFFFFFFFF' '1000000000000001' '1111111111111111' '1111111111111111' '0123456789ABCDEF' '0000000000000000' '0123456789ABCDEF' '01A1D6D039776742' '5CD54CA83DEF57DA' '0248D43806F67172' '51454B582DDF440A' '42FD443059577FA2' '059B5E0851CF143A' '0756D8E0774761D2' '762514B829BF486A' '3BDD119049372802' '26955F6835AF609A' '164D5E404F275232' '6B056E18759F5CCA' '004BD6EF09176062' '480D39006EE762F2' '437540C8698F3CFA' '072D43A077075292' '02FE55778117F12A' '1D9D5C5018F728C2' '305532286D6F295A' '0123456789ABCDEF' '0123456789ABCDEF' '0123456789ABCDEF' 'FFFFFFFFFFFFFFFF' '0000000000000000' '0000000000000000' 'FFFFFFFFFFFFFFFF'). tmpClear do: [ :each | | array tmpByteArray | array := WordArray new: 2. array at: 1 put: ((ByteArray fromHexString: (each copyFrom: 1 to: 8)) unsignedLongAt: 1 bigEndian: true). array at: 2 put: ((ByteArray fromHexString: (each copyFrom: 9 to: 16)) unsignedLongAt: 1 bigEndian: true). clear add: array ]! ----- Method: BlowfishProfiling>>initializeEncrypted (in category 'as yet unclassified') ----- initializeEncrypted | tmpEncrypted | encrypted := OrderedCollection new. tmpEncrypted := #('4EF997456198DD78' '51866FD5B85ECB8A' '7D856F9A613063F2' '2466DD878B963C9D' '61F9C3802281B096' '7D0CC630AFDA1EC7' '4EF997456198DD78' '0ACEAB0FC6A0A28D' '59C68245EB05282B' 'B1B8CC0B250F09A0' '1730E5778BEA1DA4' 'A25E7856CF2651EB' '353882B109CE8F1A' '48F4D0884C379918' '432193B78951FC98' '13F04154D69D1AE5' '2EEDDA93FFD39C79' 'D887E0393C2DA6E3' '5F99D04F5B163969' '4A057A3B24D3977B' '452031C1E4FADA8E' '7555AE39F59B87BD' '53C55F9CB49FC019' '7A8E7BFA937E89A3' 'CF9C5D7A4986ADB5' 'D1ABB290658BC778' '55CB3774D13EF201' 'FA34EC4847B268B2' 'A790795108EA3CAE' 'C39E072D9FAC631D' '014933E0CDAFF6E4' 'F21E9A77B71C49BC' '245946885754369A' '6B5C5A9C5D9E0A5A'). tmpEncrypted do: [ :each | | array tmpByteArray | array := WordArray new: 2. array at: 1 put: ((ByteArray fromHexString: (each copyFrom: 1 to: 8)) unsignedLongAt: 1 bigEndian: true). array at: 2 put: ((ByteArray fromHexString: (each copyFrom: 9 to: 16)) unsignedLongAt: 1 bigEndian: true). encrypted add: array ]! ----- Method: BlowfishProfiling>>initializeKeys (in category 'as yet unclassified') ----- initializeKeys | tempKeys | keys := OrderedCollection new. tempKeys := #('0000000000000000' 'FFFFFFFFFFFFFFFF' '3000000000000000' '1111111111111111' '0123456789ABCDEF' '1111111111111111' '0000000000000000' 'FEDCBA9876543210' '7CA110454A1A6E57' '0131D9619DC1376E' '07A1133E4A0B2686' '3849674C2602319E' '04B915BA43FEB5B6' '0113B970FD34F2CE' '0170F175468FB5E6' '43297FAD38E373FE' '07A7137045DA2A16' '04689104C2FD3B2F' '37D06BB516CB7546' '1F08260D1AC2465E' '584023641ABA6176' '025816164629B007' '49793EBC79B3258F' '4FB05E1515AB73A7' '49E95D6D4CA229BF' '018310DC409B26D6' '1C587F1C13924FEF' '0101010101010101' '1F1F1F1F0E0E0E0E' 'E0FEE0FEF1FEF1FE' '0000000000000000' 'FFFFFFFFFFFFFFFF' '0123456789ABCDEF' 'FEDCBA9876543210'). tempKeys do: [ :each | keys add: (ByteArray fromHexString: each) ]! ----- Method: BlowfishProfiling>>longDecryptionTest (in category 'as yet unclassified') ----- longDecryptionTest (1 to: keys size) do: [ :each | | key clearText cipherText enc | key := keys at: each. clearText := clear at: each. cipherText := encrypted at: each. enc := Blowfish decrypt: cipherText with: key ]! ----- Method: BlowfishProfiling>>longEncryptionTest (in category 'as yet unclassified') ----- longEncryptionTest (1 to: keys size) do: [ :each | | key clearText cipherText enc | key := keys at: each. clearText := clear at: each. cipherText := encrypted at: each. enc := Blowfish encrypt: clearText with: key ]! Object subclass: #DESBitPermutation instanceVariableNames: 'tables' classVariableNames: 'ChunkBits ChunkMask' poolDictionaries: '' category: 'CryptographyCiphers-DES'! !DESBitPermutation commentStamp: 'hmm 3/26/2002 18:15' prior: 0! Instances of this class can be used to permute bits in an integer according to a predefined mapping. It's used for DES encryption in several places.! ----- Method: DESBitPermutation class>>fromBitIndexes: (in category 'instance creation') ----- fromBitIndexes: aCollection "aCollection are bit indexes counting from the right, unlike the DES spec which counts from the left" "Example: the key permutation table for DES self fromBitIndexes: (#( 57 49 41 33 25 17 9 1 58 50 42 34 26 18 10 2 59 51 43 35 27 19 11 3 60 52 44 36 63 55 47 39 31 23 15 7 62 54 46 38 30 22 14 6 61 53 45 37 29 21 13 5 28 20 12 4) reverse collect: [:i | 64-i])" | permutation | permutation := self new initialize. aCollection doWithIndex: [:srcBit :dstBit | permutation map: srcBit to: dstBit-1]. ^permutation! ----- Method: DESBitPermutation class>>fromDESBitIndexes:sourceWidth: (in category 'instance creation') ----- fromDESBitIndexes: aCollection sourceWidth: sourceWidth "aCollection are bit indexes counting from the right, unlike the DES spec which counts from the left" "Example: the key permutation table for DES self fromDESBitIndexes: #( 57 49 41 33 25 17 9 1 58 50 42 34 26 18 10 2 59 51 43 35 27 19 11 3 60 52 44 36 63 55 47 39 31 23 15 7 62 54 46 38 30 22 14 6 61 53 45 37 29 21 13 5 28 20 12 4) sourceWidth: 64" ^self fromBitIndexes: (aCollection reverse collect: [:i | sourceWidth-i])! ----- Method: DESBitPermutation class>>initialize (in category 'class initialization') ----- initialize "DESBitPermutation initialize" ChunkBits := 6. ChunkMask := (1 bitShift: ChunkBits) - 1! ----- Method: DESBitPermutation>>initialize (in category 'initialize-release') ----- initialize tables := #()! ----- Method: DESBitPermutation>>map:to: (in category 'initialize-release') ----- map: srcBit to: dstBit | i mask array bit | i := srcBit // ChunkBits + 1. [tables size < i] whileTrue: [tables := tables copyWith: (Array new: ChunkMask+1 withAll: 0)]. mask := 1 bitShift: (srcBit \\ ChunkBits). array := tables at: i. bit := 1 bitShift: dstBit. 0 to: ChunkMask do: [:index | (index bitAnd: mask) = mask ifTrue: [ array at: index+1 put: ((array at: index+1) bitOr: bit)]]! ----- Method: DESBitPermutation>>permute: (in category 'permuting') ----- permute: input | output shift bits | output := 0. shift := 0. tables do: [:array | bits := (input bitShift: shift) bitAnd: ChunkMask. output := output + (array at: bits+1). shift := shift - ChunkBits]. ^output! Object subclass: #KeyHolder instanceVariableNames: 'data random randomChangeProcess' classVariableNames: '' poolDictionaries: '' category: 'CryptographyCiphers-ARC2'! !KeyHolder commentStamp: 'RJT 2/9/2007 11:10' prior: 0! A KeyHolder is a construct that holds key information safely in memory. The key is never stored in plain text in memory. The system encrypts the key using two different objects and therefore two different memory locations. A random key is generated and used to encrypt the key. That random key is changed every 100ms. To retrieve the key send the message #key. You must send in a byteArray. If you are storing a key that is a string then do: KeyHolder holdKey: 'aPassword' asByteArray. when asking for key you will get back aByteArray so if you are looking for a string use aByteArray := aKeyHolder key. pKey := aByteArray asString. aByteArray destroy. When you are done with the byteArray send the message destroy to it, to keep your secret key from being written to disk. Never leave your key in memory for very log. Get it, use it and destroy it as quickly as possible in the same message chain. If you no longer need this keyHolder you must send the message destroy to it to stop the process and wipe the memory clean. Instance Variables data: KeyHolderData random: aByteArray randomChangeProcess: aProcess data - holds onto an instance of KeyHolderData which holds your encrypted key. random - the key used to encrypt your key randomChangeProcess - the process that changes random ! ----- Method: KeyHolder class>>LICENSE (in category 'LICENSE') ----- LICENSE "http://www.opensource.org/licenses/mit-license.php" ^'Copyright (c) 2006 Ron Teitelbaum * US Medical Record Specialists * [hidden email] Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.' ! ----- Method: KeyHolder class>>holdKey: (in category 'instance creation') ----- holdKey: aKey "store a key scrambled in memory" ^self new data: (KeyHolderData new); encryptKey: aKey; randomChangeLoop; yourself! ----- Method: KeyHolder class>>readFromFile:password: (in category 'instance creation') ----- readFromFile: aFileName password: aPassword "this method takes a long time on purpose, the idea is to increase the amount of time and resources needed to crack password" | pwHash cipher cData pwHashAndSalt pwSalt eData aStream aKeyHolder | [eData := ((aStream := FileStream fileNamed: aFileName) ifNil: [^nil]) binary contents asByteArray] ensure: [aStream close]. pwSalt := eData copyFrom: eData size - 31 to: eData size. eData := eData copyFrom: 1 to: eData size - 32. pwHashAndSalt := PasswordSaltAndStretch hashForPassword: aPassword s: pwSalt. pwHash := pwHashAndSalt key. pwSalt := pwHashAndSalt value. cipher := (TripleDES key: pwHash) cbc. cData := cipher decrypt: eData. aKeyHolder := self holdKey: cData. cData destroy. ^aKeyHolder ! ----- Method: KeyHolder>>data (in category 'accessing') ----- data "Answer the value of data" ^ data! ----- Method: KeyHolder>>data: (in category 'accessing') ----- data: anObject "Set the value of data" data := anObject! ----- Method: KeyHolder>>destroy (in category 'initialize-release') ----- destroy self randomChangeProcess terminate. self randomChangeProcess: nil. self random destroy. self data key destroy. self data: nil.! ----- Method: KeyHolder>>encryptKey: (in category 'services') ----- encryptKey: pKey | eKey | eKey := (TripleDES key: self random) cbc encrypt: pKey. self data key: eKey! ----- Method: KeyHolder>>initialize (in category 'initialize-release') ----- initialize self random: (SecureRandom picker nextBytesNonZero: 32)! ----- Method: KeyHolder>>key (in category 'services') ----- key ^[(TripleDES key: self random) cbc decrypt: self data key] on: CryptographyError do: [:ex | ex retry]! ----- Method: KeyHolder>>random (in category 'accessing') ----- random "Answer the value of random" ^ random! ----- Method: KeyHolder>>random: (in category 'accessing') ----- random: anObject "Set the value of random" random := anObject! ----- Method: KeyHolder>>randomChangeLoop (in category 'processes') ----- randomChangeLoop "This loop changes the random and reencrypts the data every 100ms" | pKey randomGenerator | self randomChangeProcess: ([ randomGenerator := SecureRandom picker. [ pKey := self key. self random: (randomGenerator nextBytesNonZero: 32). self encryptKey: pKey. pKey destroy. (Delay forMilliseconds: 100) wait. true. ] whileTrue. ] forkAt: Processor highIOPriority)! ----- Method: KeyHolder>>randomChangeProcess (in category 'accessing') ----- randomChangeProcess "Answer the value of randomChangeProcess" ^ randomChangeProcess! ----- Method: KeyHolder>>randomChangeProcess: (in category 'accessing') ----- randomChangeProcess: anObject "Set the value of randomChangeProcess" randomChangeProcess := anObject! ----- Method: KeyHolder>>writeToFile:password: (in category 'services') ----- writeToFile: aFileName password: aPassword "this method takes a long time on purpose, the idea is to increase the amount of time and resources needed to crack password" | pwHash cipher cData pwHashAndSalt pwSalt | pwHashAndSalt := PasswordSaltAndStretch hashForPassword: aPassword. pwHash := pwHashAndSalt key. pwSalt := pwHashAndSalt value. cipher := (TripleDES key: pwHash) cbc. cData := cipher encrypt: self key. (FileStream forceNewFileNamed: aFileName) nextPutAll: cData; nextPutAll: pwSalt; close. ! Object subclass: #KeyHolderData instanceVariableNames: 'key' classVariableNames: '' poolDictionaries: '' category: 'CryptographyCiphers-ARC2'! !KeyHolderData commentStamp: 'RJT 2/9/2007 11:17' prior: 0! A KeyHolderData is used by KeyHolder see comments there. Instance Variables key: <ByteArray> key - key that was encrypted by KeyHolder. This value is changed frequently by KeyHolder. ! ----- Method: KeyHolderData class>>LICENSE (in category 'LICENSE') ----- LICENSE "http://www.opensource.org/licenses/mit-license.php" ^'Copyright (c) 2006 Ron Teitelbaum * US Medical Record Specialists * [hidden email] Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.' ! ----- Method: KeyHolderData>>key (in category 'accessing') ----- key "Answer the value of key" ^ key! ----- Method: KeyHolderData>>key: (in category 'accessing') ----- key: anObject "Set the value of key" key := anObject! BlockCipher subclass: #ARC2 instanceVariableNames: 'T1 T8 TM keyHolder j' classVariableNames: 'PITABLE' poolDictionaries: '' category: 'CryptographyCiphers-ARC2'! !ARC2 commentStamp: 'RJT 3/30/2007 09:48' prior: 0! Network Working Group R. Rivest Request for Comments: 2268 MIT Laboratory for Computer Science Category: Informational and RSA Data Security, Inc. March 1998 A Description of the RC2(r) Encryption Algorithm Status of this Memo This memo provides information for the Internet community. It does not specify an Internet standard of any kind. Distribution of this memo is unlimited. Copyright Notice Copyright (C) The Internet Society (1998). All Rights Reserved. 1. Introduction This memo is an RSA Laboratories Technical Note. It is meant for informational use by the Internet community. This memo describes a conventional (secret-key) block encryption algorithm, called RC2, which may be considered as a proposal for a DES replacement. The input and output block sizes are 64 bits each. The key size is variable, from one byte up to 128 bytes, although the current implementation uses eight bytes. The algorithm is designed to be easy to implement on 16-bit microprocessors. On an IBM AT, the encryption runs about twice as fast as DES (assuming that key expansion has been done). 1.1 Algorithm description We use the term "word" to denote a 16-bit quantity. The symbol + will denote twos-complement addition. The symbol & will denote the bitwise "and" operation. The term XOR will denote the bitwise "exclusive-or" operation. The symbol ~ will denote bitwise complement. The symbol ^ will denote the exponentiation operation. The term MOD will denote the modulo operation. There are three separate algorithms involved: Key expansion. This takes a (variable-length) input key and produces an expanded key consisting of 64 words K[0],...,K[63]. Rivest Informational [Page 1] RFC 2268 RC2(r) Encryption Algorithm March 1998 Encryption. This takes a 64-bit input quantity stored in words R[0], ..., R[3] and encrypts it "in place" (the result is left in R[0], ..., R[3]). Decryption. The inverse operation to encryption. 2. Key expansion Since we will be dealing with eight-bit byte operations as well as 16-bit word operations, we will use two alternative notations for referring to the key buffer: For word operations, we will refer to the positions of the buffer as K[0], ..., K[63]; each K[i] is a 16-bit word. For byte operations, we will refer to the key buffer as L[0], ..., L[127]; each L[i] is an eight-bit byte. These are alternative views of the same data buffer. At all times it will be true that K[i] = L[2*i] + 256*L[2*i+1]. (Note that the low-order byte of each K word is given before the high-order byte.) We will assume that exactly T bytes of key are supplied, for some T in the range 1 <= T <= 128. (Our current implementation uses T = 8.) However, regardless of T, the algorithm has a maximum effective key length in bits, denoted T1. That is, the search space is 2^(8*T), or 2^T1, whichever is smaller. The purpose of the key-expansion algorithm is to modify the key buffer so that each bit of the expanded key depends in a complicated way on every bit of the supplied input key. The key expansion algorithm begins by placing the supplied T-byte key into bytes L[0], ..., L[T-1] of the key buffer. The key expansion algorithm then computes the effective key length in bytes T8 and a mask TM based on the effective key length in bits T1. It uses the following operations: T8 = (T1+7)/8; TM = 255 MOD 2^(8 + T1 - 8*T8); Thus TM has its 8 - (8*T8 - T1) least significant bits set. Rivest Informational [Page 2] RFC 2268 RC2(r) Encryption Algorithm March 1998 For example, with an effective key length of 64 bits, T1 = 64, T8 = 8 and TM = 0xff. With an effective key length of 63 bits, T1 = 63, T8 = 8 and TM = 0x7f. Here PITABLE[0], ..., PITABLE[255] is an array of "random" bytes based on the digits of PI = 3.14159... . More precisely, the array PITABLE is a random permutation of the values 0, ..., 255. Here is the PITABLE in hexadecimal notation: 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: d9 78 f9 c4 19 dd b5 ed 28 e9 fd 79 4a a0 d8 9d 10: c6 7e 37 83 2b 76 53 8e 62 4c 64 88 44 8b fb a2 20: 17 9a 59 f5 87 b3 4f 13 61 45 6d 8d 09 81 7d 32 30: bd 8f 40 eb 86 b7 7b 0b f0 95 21 22 5c 6b 4e 82 40: 54 d6 65 93 ce 60 b2 1c 73 56 c0 14 a7 8c f1 dc 50: 12 75 ca 1f 3b be e4 d1 42 3d d4 30 a3 3c b6 26 60: 6f bf 0e da 46 69 07 57 27 f2 1d 9b bc 94 43 03 70: f8 11 c7 f6 90 ef 3e e7 06 c3 d5 2f c8 66 1e d7 80: 08 e8 ea de 80 52 ee f7 84 aa 72 ac 35 4d 6a 2a 90: 96 1a d2 71 5a 15 49 74 4b 9f d0 5e 04 18 a4 ec a0: c2 e0 41 6e 0f 51 cb cc 24 91 af 50 a1 f4 70 39 b0: 99 7c 3a 85 23 b8 b4 7a fc 02 36 5b 25 55 97 31 c0: 2d 5d fa 98 e3 8a 92 ae 05 df 29 10 67 6c ba c9 d0: d3 00 e6 cf e1 9e a8 2c 63 16 01 3f 58 e2 89 a9 e0: 0d 38 34 1b ab 33 ff b0 bb 48 0c 5f b9 b1 cd 2e f0: c5 f3 db 47 e5 a5 9c 77 0a a6 20 68 fe 7f c1 ad The key expansion operation consists of the following two loops and intermediate step: for i = T, T+1, ..., 127 do L[i] = PITABLE[L[i-1] + L[i-T]]; L[128-T8] = PITABLE[L[128-T8] & TM]; for i = 127-T8, ..., 0 do L[i] = PITABLE[L[i+1] XOR L[i+T8]]; (In the first loop, the addition of L[i-1] and L[i-T] is performed modulo 256.) The "effective key" consists of the values L[128-T8],..., L[127]. The intermediate step's bitwise "and" operation reduces the search space for L[128-T8] so that the effective number of key bits is T1. The expanded key depends only on the effective key bits, regardless Rivest Informational [Page 3] RFC 2268 RC2(r) Encryption Algorithm March 1998 of the supplied key K. Since the expanded key is not itself modified during encryption or decryption, as a pragmatic matter one can expand the key just once when encrypting or decrypting a large block of data. 3. Encryption algorithm The encryption operation is defined in terms of primitive "mix" and "mash" operations. Here the expression "x rol k" denotes the 16-bit word x rotated left by k bits, with the bits shifted out the top end entering the bottom end. 3.1 Mix up R[i] The primitive "Mix up R[i]" operation is defined as follows, where s[0] is 1, s[1] is 2, s[2] is 3, and s[3] is 5, and where the indices of the array R are always to be considered "modulo 4," so that R[i-1] refers to R[3] if i is 0 (these values are "wrapped around" so that R always has a subscript in the range 0 to 3 inclusive): R[i] = R[i] + K[j] + (R[i-1] & R[i-2]) + ((~R[i-1]) & R[i-3]); j = j + 1; R[i] = R[i] rol s[i]; In words: The next key word K[j] is added to R[i], and j is advanced. Then R[i-1] is used to create a "composite" word which is added to R[i]. The composite word is identical with R[i-2] in those positions where R[i-1] is one, and identical to R[i-3] in those positions where R[i-1] is zero. Then R[i] is rotated left by s[i] bits (bits rotated out the left end of R[i] are brought back in at the right). Here j is a "global" variable so that K[j] is always the first key word in the expanded key which has not yet been used in a "mix" operation. 3.2 Mixing round A "mixing round" consists of the following operations: Mix up R[0] Mix up R[1] Mix up R[2] Mix up R[3] Rivest Informational [Page 4] RFC 2268 RC2(r) Encryption Algorithm March 1998 3.3 Mash R[i] The primitive "Mash R[i]" operation is defined as follows (using the previous conventions regarding subscripts for R): R[i] = R[i] + K[R[i-1] & 63]; In words: R[i] is "mashed" by adding to it one of the words of the expanded key. The key word to be used is determined by looking at the low-order six bits of R[i-1], and using that as an index into the key array K. 3.4 Mashing round A "mashing round" consists of: Mash R[0] Mash R[1] Mash R[2] Mash R[3] 3.5 Encryption operation The entire encryption operation can now be described as follows. Here j is a global integer variable which is affected by the mixing operations. 1. Initialize words R[0], ..., R[3] to contain the 64-bit input value. 2. Expand the key, so that words K[0], ..., K[63] become defined. 3. Initialize j to zero. 4. Perform five mixing rounds. 5. Perform one mashing round. 6. Perform six mixing rounds. 7. Perform one mashing round. 8. Perform five mixing rounds. Note that each mixing round uses four key words, and that there are 16 mixing rounds altogether, so that each key word is used exactly Rivest Informational [Page 5] RFC 2268 RC2(r) Encryption Algorithm March 1998 once in a mixing round. The mashing rounds will refer to up to eight of the key words in a data-dependent manner. (There may be repetitions, and the actual set of words referred to will vary from encryption to encryption.) 4. Decryption algorithm The decryption operation is defined in terms of primitive operations that undo the "mix" and "mash" operations of the encryption algorithm. They are named "r-mix" and "r-mash" (r- denotes the reverse operation). Here the expression "x ror k" denotes the 16-bit word x rotated right by k bits, with the bits shifted out the bottom end entering the top end. 4.1 R-Mix up R[i] The primitive "R-Mix up R[i]" operation is defined as follows, where s[0] is 1, s[1] is 2, s[2] is 3, and s[3] is 5, and where the indices of the array R are always to be considered "modulo 4," so that R[i-1] refers to R[3] if i is 0 (these values are "wrapped around" so that R always has a subscript in the range 0 to 3 inclusive): R[i] = R[i] ror s[i]; R[i] = R[i] - K[j] - (R[i-1] & R[i-2]) - ((~R[i-1]) & R[i-3]); j = j - 1; In words: R[i] is rotated right by s[i] bits (bits rotated out the right end of R[i] are brought back in at the left). Here j is a "global" variable so that K[j] is always the key word with greatest index in the expanded key which has not yet been used in a "r-mix" operation. The key word K[j] is subtracted from R[i], and j is decremented. R[i-1] is used to create a "composite" word which is subtracted from R[i]. The composite word is identical with R[i-2] in those positions where R[i-1] is one, and identical to R[i-3] in those positions where R[i-1] is zero. 4.2 R-Mixing round An "r-mixing round" consists of the following operations: R-Mix up R[3] R-Mix up R[2] R-Mix up R[1] R-Mix up R[0] Rivest Informational [Page 6] RFC 2268 RC2(r) Encryption Algorithm March 1998 4.3 R-Mash R[i] The primitive "R-Mash R[i]" operation is defined as follows (using the previous conventions regarding subscripts for R): R[i] = R[i] - K[R[i-1] & 63]; In words: R[i] is "r-mashed" by subtracting from it one of the words of the expanded key. The key word to be used is determined by looking at the low-order six bits of R[i-1], and using that as an index into the key array K. 4.4 R-Mashing round An "r-mashing round" consists of: R-Mash R[3] R-Mash R[2] R-Mash R[1] R-Mash R[0] 4.5 Decryption operation The entire decryption operation can now be described as follows. Here j is a global integer variable which is affected by the mixing operations. 1. Initialize words R[0], ..., R[3] to contain the 64-bit ciphertext value. 2. Expand the key, so that words K[0], ..., K[63] become defined. 3. Initialize j to 63. 4. Perform five r-mixing rounds. 5. Perform one r-mashing round. 6. Perform six r-mixing rounds. 7. Perform one r-mashing round. 8. Perform five r-mixing rounds. 5. Test vectors Test vectors for encryption with RC2 are provided below. Rivest Informational [Page 7] RFC 2268 RC2(r) Encryption Algorithm March 1998 All quantities are given in hexadecimal notation. Key length (bytes) = 8 Effective key length (bits) = 63 Key = 00000000 00000000 Plaintext = 00000000 00000000 Ciphertext = ebb773f9 93278eff Key length (bytes) = 8 Effective key length (bits) = 64 Key = ffffffff ffffffff Plaintext = ffffffff ffffffff Ciphertext = 278b27e4 2e2f0d49 Key length (bytes) = 8 Effective key length (bits) = 64 Key = 30000000 00000000 Plaintext = 10000000 00000001 Ciphertext = 30649edf 9be7d2c2 Key length (bytes) = 1 Effective key length (bits) = 64 Key = 88 Plaintext = 00000000 00000000 Ciphertext = 61a8a244 adacccf0 Key length (bytes) = 7 Effective key length (bits) = 64 Key = 88bca90e 90875a Plaintext = 00000000 00000000 Ciphertext = 6ccf4308 974c267f Key length (bytes) = 16 Effective key length (bits) = 64 Key = 88bca90e 90875a7f 0f79c384 627bafb2 Plaintext = 00000000 00000000 Ciphertext = 1a807d27 2bbe5db1 Key length (bytes) = 16 Effective key length (bits) = 128 Key = 88bca90e 90875a7f 0f79c384 627bafb2 Plaintext = 00000000 00000000 Ciphertext = 2269552a b0f85ca6 Key length (bytes) = 33 Effective key length (bits) = 129 Key = 88bca90e 90875a7f 0f79c384 627bafb2 16f80a6f 85920584 c42fceb0 be255daf 1e Rivest Informational [Page 8] RFC 2268 RC2(r) Encryption Algorithm March 1998 Plaintext = 00000000 00000000 Ciphertext = 5b78d3a4 3dfff1f1 6. RC2 Algorithm Object Identifier The Object Identifier for RC2 in cipher block chaining mode is rc2CBC OBJECT IDENTIFIER ::= {iso(1) member-body(2) US(840) rsadsi(113549) encryptionAlgorithm(3) 2} RC2-CBC takes parameters RC2-CBCParameter ::= CHOICE { iv IV, params SEQUENCE { version RC2Version, iv IV } } where IV ::= OCTET STRING -- 8 octets RC2Version ::= INTEGER -- 1-1024 RC2 in CBC mode has two parameters: an 8-byte initialization vector (IV) and a version number in the range 1-1024 which specifies in a roundabout manner the number of effective key bits to be used for the RC2 encryption/decryption. The correspondence between effective key bits and version number is as follows: 1. If the number EKB of effective key bits is in the range 1-255, then the version number is given by Table[EKB], where the 256-byte translation table Table[] is specified below. Table[] specifies a permutation on the numbers 0-255; note that it is not the same table that appears in the key expansion phase of RC2. 2. If the number EKB of effective key bits is in the range 256-1024, then the version number is simply EKB. The default number of effective key bits for RC2 is 32. If RC2-CBC is being performed with 32 effective key bits, the parameters should be supplied as a simple IV, rather than as a SEQUENCE containing a version and an IV. Rivest Informational [Page 9] RFC 2268 RC2(r) Encryption Algorithm March 1998 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: bd 56 ea f2 a2 f1 ac 2a b0 93 d1 9c 1b 33 fd d0 10: 30 04 b6 dc 7d df 32 4b f7 cb 45 9b 31 bb 21 5a 20: 41 9f e1 d9 4a 4d 9e da a0 68 2c c3 27 5f 80 36 30: 3e ee fb 95 1a fe ce a8 34 a9 13 f0 a6 3f d8 0c 40: 78 24 af 23 52 c1 67 17 f5 66 90 e7 e8 07 b8 60 50: 48 e6 1e 53 f3 92 a4 72 8c 08 15 6e 86 00 84 fa 60: f4 7f 8a 42 19 f6 db cd 14 8d 50 12 ba 3c 06 4e 70: ec b3 35 11 a1 88 8e 2b 94 99 b7 71 74 d3 e4 bf 80: 3a de 96 0e bc 0a ed 77 fc 37 6b 03 79 89 62 c6 90: d7 c0 d2 7c 6a 8b 22 a3 5b 05 5d 02 75 d5 61 e3 a0: 18 8f 55 51 ad 1f 0b 5e 85 e5 c2 57 63 ca 3d 6c b0: b4 c5 cc 70 b2 91 59 0d 47 20 c8 4f 58 e0 01 e2 c0: 16 38 c4 6f 3b 0f 65 46 be 7e 2d 7b 82 f9 40 b5 d0: 1d 73 f8 eb 26 c7 87 97 25 54 b1 28 aa 98 9d a5 e0: 64 6d 7a d4 10 81 44 ef 49 d6 ae 2e dd 76 5c 2f f0: a7 1c c9 09 69 9a 83 cf 29 39 b9 e9 4c ff 43 ab A. Intellectual Property Notice RC2 is a registered trademark of RSA Data Security, Inc. RSA's copyrighted RC2 software is available under license from RSA Data Security, Inc. B. Author's Address Ron Rivest RSA Laboratories 100 Marine Parkway, #500 Redwood City, CA 94065 USA Phone: (650) 595-7703 EMail: [hidden email] Rivest Informational [Page 10] RFC 2268 RC2(r) Encryption Algorithm March 1998 C. Full Copyright Statement Copyright (C) The Internet Society (1998). All Rights Reserved. This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English. The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns. This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Rivest Informational [Page 11]! ----- Method: ARC2 class>>LICENSE (in category 'LICENSE') ----- LICENSE "http://www.opensource.org/licenses/mit-license.php" ^'Copyright (c) 2006 Ron Teitelbaum * US Medical Record Specialists * [hidden email] Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.' ! ----- Method: ARC2 class>>PITABLE (in category 'constants') ----- PITABLE PITABLE isNil ifTrue: [ PITABLE := #(217 120 249 196 25 221 181 237 40 233 253 121 74 160 216 157 198 126 55 131 43 118 83 142 98 76 100 136 68 139 251 162 23 154 89 245 135 179 79 19 97 69 109 141 9 129 125 50 189 143 64 235 134 183 123 11 240 149 33 34 92 107 78 130 84 214 101 147 206 96 178 28 115 86 192 20 167 140 241 220 18 117 202 31 59 190 228 209 66 61 212 48 163 60 182 38 111 191 14 218 70 105 7 87 39 242 29 155 188 148 67 3 248 17 199 246 144 239 62 231 6 195 213 47 200 102 30 215 8 232 234 222 128 82 238 247 132 170 114 172 53 77 106 42 150 26 210 113 90 21 73 116 75 159 208 94 4 24 164 236 194 224 65 110 15 81 203 204 36 145 175 80 161 244 112 57 153 124 58 133 35 184 180 122 252 2 54 91 37 85 151 49 45 93 250 152 227 138 146 174 5 223 41 16 103 108 186 201 211 0 230 207 225 158 168 44 99 22 1 63 88 226 137 169 13 56 52 27 171 51 255 176 187 72 12 95 185 177 205 46 197 243 219 71 229 165 156 119 10 166 32 104 254 127 193 173) asByteArray]. ^ PITABLE! ----- Method: ARC2 class>>key: (in category 'instance creation') ----- key: aByteArray ^ self new key: aByteArray; T1: 128; setKeySize; yourself! ----- Method: ARC2 class>>key:effectiveKeyLength: (in category 'instance creation') ----- key: aByteArray effectiveKeyLength: aKeyStrength ^ self new key: aByteArray; T1: aKeyStrength; setKeySize; yourself! ----- Method: ARC2 class>>rotate16BitWord:leftBy: (in category 'support') ----- rotate16BitWord: a16BitWord leftBy: bitCount | s1 s2 aBitCount | aBitCount := bitCount \\ 16. aBitCount < 0 ifTrue: [aBitCount := aBitCount + 16]. s1 := aBitCount. s2 := s1 - 16. ^((a16BitWord bitShift: s1) bitAnd: 16rFFFF) bitOr: (a16BitWord bitShift: s2).! ----- Method: ARC2>>T1 (in category 'accessing') ----- T1 "Answer the value of T1" ^ T1! ----- Method: ARC2>>T1: (in category 'accessing') ----- T1: anObject "Set the value of T1" T1 := anObject! ----- Method: ARC2>>T8 (in category 'accessing') ----- T8 "Answer the value of T8" ^ T8! ----- Method: ARC2>>T8: (in category 'accessing') ----- T8: anObject "Set the value of T8" T8 := anObject! ----- Method: ARC2>>TM (in category 'accessing') ----- TM "Answer the value of TM" ^ TM! ----- Method: ARC2>>TM: (in category 'accessing') ----- TM: anObject "Set the value of TM" TM := anObject! ----- Method: ARC2>>blockSize (in category 'initialize-release') ----- blockSize ^8! ----- Method: ARC2>>decryptBlock: (in category 'encryption/decryption') ----- decryptBlock: cipherText | result | result := self decryptBlock: cipherText key: self expandedKey. result withIndexDo: [:a :i | cipherText at: i put: a ]. ^cipherText! ----- Method: ARC2>>decryptBlock:key: (in category 'encryption/decryption') ----- decryptBlock: plainText key: expandedKeys "The entire decryption operation can now be described as follows. Here j is a global integer variable which is affected by the mixing operations. 1. Initialize words R[0], ..., R[3] to contain the 64-bit ciphertext value. 2. Expand the key, so that words K[0], ..., K[63] become defined. 3. Initialize j to 63. 4. Perform five r-mixing rounds. 5. Perform one r-mashing round. 6. Perform six r-mixing rounds. 7. Perform one r-mashing round. 8. Perform five r-mixing rounds." | cText rStream result | self j: 63. cText := plainText. rStream := cText readStream. result := ByteArray new. [rStream atEnd] whileFalse: [ result := result , ((rStream nextLittleEndianNumber: 2) asByteArrayOfSize: 2) ]. cText := result. 1 to: 5 do: [:i | cText := self rMixUp: cText withKeys: expandedKeys ]. cText := self rMash: cText withKeys: expandedKeys. 1 to: 6 do: [:i | cText := self rMixUp: cText withKeys: expandedKeys ]. cText := self rMash: cText withKeys: expandedKeys. 1 to: 5 do: [:i | cText := self rMixUp: cText withKeys: expandedKeys ]. rStream := cText readStream. result := ByteArray new. [rStream atEnd] whileFalse: [ result := result , ((rStream nextLittleEndianNumber: 2) asByteArrayOfSize: 2) ]. ^result ! ----- Method: ARC2>>destroy (in category 'services') ----- destroy self keyHolder destroy.! ----- Method: ARC2>>encryptBlock: (in category 'encryption/decryption') ----- encryptBlock: plainText | result | result := self encryptBlock: plainText key: self expandedKey. result withIndexDo: [:a :i | plainText at: i put: a ]. ^plainText! ----- Method: ARC2>>encryptBlock:key: (in category 'encryption/decryption') ----- encryptBlock: plainText key: expandedKeys "The entire encryption operation can now be described as follows. Here j is a global integer variable which is affected by the mixing operations. 1. Initialize words R[0], ..., R[3] to contain the 64-bit input value. 2. Expand the key, so that words K[0], ..., K[63] become defined. 3. Initialize j to zero. 4. Perform five mixing rounds. 5. Perform one mashing round. 6. Perform six mixing rounds. 7. Perform one mashing round. 8. Perform five mixing rounds." | cText rStream result | self j: 0. cText := plainText. rStream := cText readStream. result := ByteArray new. [rStream atEnd] whileFalse: [ result := result , ((rStream nextLittleEndianNumber: 2) asByteArrayOfSize:2) ]. cText := result. 1 to: 5 do: [:i | cText := self mixUp: cText withKeys: expandedKeys ]. cText := self mash: cText withKeys: expandedKeys. 1 to: 6 do: [:i | cText := self mixUp: cText withKeys: expandedKeys ]. cText := self mash: cText withKeys: expandedKeys. 1 to: 5 do: [:i | cText := self mixUp: cText withKeys: expandedKeys ]. rStream := cText readStream. result := ByteArray new. [rStream atEnd] whileFalse: [ result := result , ((rStream nextLittleEndianNumber: 2) asByteArrayOfSize: 2) ]. ^result ! ----- Method: ARC2>>expandedKey (in category 'services') ----- expandedKey "for i = T, T+1, ..., 127 do L[i] = PITABLE[L[i-1] + L[i-T]];" | keyBuffer aT v1 v2 pos byteStream result | keyBuffer := (self key reverse asByteArrayOfSize: 128) reverse. aT := self key size. aT to: 127 do: [:i | v1 := keyBuffer at: (i -1) + 1. v2 := keyBuffer at: (i - aT) + 1. keyBuffer at: (i+1) put: (self class PITABLE at: (((v1 + v2) \\ 256) + 1)). ]. "L[128-T8] = PITABLE[L[128-T8] & TM];" pos := (128 - self T8) + 1. keyBuffer at: pos put: (self class PITABLE at: (((keyBuffer at: pos) bitAnd: self TM) + 1)). "for i = 127-T8, ..., 0 do L[i] = PITABLE[L[i+1] XOR L[i+T8]]; " (127 - self T8) to: 0 by: -1 do: [:i | keyBuffer at: (i+1) put: (self class PITABLE at: (((keyBuffer at: ((i + 1) +1)) bitXor: (keyBuffer at: ((i + self T8)+1))) +1)) ]. byteStream := keyBuffer readStream. result := OrderedCollection new: byteStream size. [byteStream atEnd] whileFalse: [ result add: (byteStream next + (byteStream next bitShift: 8)) "Little Endian" ]. ^result ! ----- Method: ARC2>>initialize (in category 'initialize-release') ----- initialize self j: 0.! ----- Method: ARC2>>j (in category 'accessing') ----- j "Answer the value of j" ^ j! ----- Method: ARC2>>j: (in category 'accessing') ----- j: anInteger "Set the value of j" j := anInteger! ----- Method: ARC2>>key (in category 'key') ----- key ^self keyHolder key! ----- Method: ARC2>>key: (in category 'key') ----- key: aByteArray self keyHolder: (KeyHolder holdKey: aByteArray)! ----- Method: ARC2>>keyHolder (in category 'accessing') ----- keyHolder "Answer the value of keyHolder" ^ keyHolder! ----- Method: ARC2>>keyHolder: (in category 'accessing') ----- keyHolder: anObject "Set the value of keyHolder" keyHolder := anObject! ----- Method: ARC2>>mash:withKeys: (in category 'services') ----- mash: a64BitWord withKeys: expandedKeys "The primitive 'Mash R[i]' operation is defined as follows (using the previous conventions regarding subscripts for R): R[i] = R[i] + K[R[i-1] & 63]; In words: R[i] is 'mashed; by adding to it one of the words of the expanded key. The key word to be used is determined by looking at the low-order six bits of R[i-1], and using that as an index into the key array K. " | aR aByteStream aRi aK result | aR := Array new: 4. aByteStream := (a64BitWord asByteArrayOfSize: 8) readStream. 1 to: 4 do: [:i | aR at: i put: ((aByteStream next bitShift: 8) + aByteStream next). ]. 0 to: 3 do: [:i | aRi := aR at: i + 1. aK := expandedKeys at: (((aR at: ((i - 1) \\ 4)+1) bitAnd: 63) + 1). aR at: i + 1 put: ((aRi + aK) bitAnd: 16rFFFF). ]. result := ByteArray new. aR do: [:a16BitWord | result := result, (a16BitWord asByteArrayOfSize: 2) ]. ^result. ! ----- Method: ARC2>>mixUp:withKeys: (in category 'services') ----- mixUp: a64BitWord withKeys: expandedKeys "The primitive 'Mix up R[i]' operation is defined as follows, where s[0] is 1, s[1] is 2, s[2] is 3, and s[3] is 5, and where the indices of the array R are always to be considered 'modulo 4,' so that R[i-1] refers to R[3] if i is 0 (these values are 'wrapped around' so that R always has a subscript in the range 0 to 3 inclusive): R[i] = R[i] + K[j] + (R[i-1] & R[i-2]) + ((~R[i-1]) & R[i-3]); j = j + 1; R[i] = R[i] rol s[i]; " | aS aR aByteStream aRi aKj aRa aRb aRc aRd si result | aS := Array with: 1 with: 2 with: 3 with: 5. aR := Array new: 4. aByteStream := (a64BitWord asByteArrayOfSize: 8) readStream. 1 to: 4 do: [:i | aR at: i put: ((aByteStream next bitShift: 8) + aByteStream next). ]. 0 to: 3 do: [:i | aRi := aR at: i +1. aKj := expandedKeys at: self j + 1. "j+1 changes offset from 0 - 3 to 1 to 4" aRa := aR at: ((i - 1 \\ 4) + 1). aRb := aR at: ((i - 2 \\ 4) + 1). aRc := aRa bitXor: 16rFFFF. aRd := aR at: ((i - 3 \\ 4) + 1). si := aS at: i +1. aR at: i+1 put: (self class rotate16BitWord: ((aRi + aKj + (aRa bitAnd: aRb) + (aRc bitAnd: aRd)) bitAnd: 16rFFFF) leftBy: si). self j: self j + 1. ]. result := ByteArray new. aR do: [:a16BitWord | result := result, (a16BitWord asByteArrayOfSize: 2) ]. ^result. ! ----- Method: ARC2>>rMash:withKeys: (in category 'services') ----- rMash: a64BitWord withKeys: expandedKeys "The primitive 'Mash R[i]' operation is defined as follows (using the previous conventions regarding subscripts for R): R[i] = R[i] - K[R[i-1] & 63]; In words: R[i] is 'mashed; by adding to it one of the words of the expanded key. The key word to be used is determined by looking at the low-order six bits of R[i-1], and using that as an index into the key array K. " | aR aByteStream aRi aK result | aR := Array new: 4. aByteStream := (a64BitWord asByteArrayOfSize: 8) readStream. 1 to: 4 do: [:i | aR at: i put: ((aByteStream next bitShift: 8) + aByteStream next). ]. 3 to: 0 by: -1 do: [:i | aRi := aR at: i + 1. aK := expandedKeys at: (((aR at: ((i - 1) \\ 4)+1) bitAnd: 63) + 1). aR at: i + 1 put: ((aRi - aK) bitAnd: 16rFFFF). ]. result := ByteArray new. aR do: [:a16BitWord | result := result, (a16BitWord asByteArrayOfSize: 2) ]. ^result. ! ----- Method: ARC2>>rMixUp:withKeys: (in category 'services') ----- rMixUp: a64BitWord withKeys: expandedKeys "The primitive 'R-Mix up R[i]' operation is defined as follows, where s[0] is 1, s[1] is 2, s[2] is 3, and s[3] is 5, and where the indices of the array R are always to be considered 'modulo 4,' so that R[i-1] refers to R[3] if i is 0 (these values are 'wrapped around' so that R always has a subscript in the range 0 to 3 inclusive): R[i] = R[i] roR s[i]; R[i] = R[i] - K[j] - (R[i-1] & R[i-2]) - ((~R[i-1]) & R[i-3]); j = j - 1; " | aS aR aByteStream aRi aKj aRa aRb aRc aRd si result | aS := Array with: 1 with: 2 with: 3 with: 5. aR := Array new: 4. aByteStream := (a64BitWord asByteArrayOfSize: 8) readStream. 1 to: 4 do: [:i | aR at: i put: ((aByteStream next bitShift: 8) + aByteStream next). ]. 3 to: 0 by: -1 do: [:i | si := aS at: i +1. aR at: i + 1 put: (self class rotate16BitWord: (aR at: i +1) leftBy: si negated). aRi := aR at: i + 1. aKj := expandedKeys at: self j + 1. "j+1 changes offset from 0 - 3 to 1 to 4" aRa := aR at: ((i - 1 \\ 4) + 1). aRb := aR at: ((i - 2 \\ 4) + 1). aRc := aRa bitXor: 16rFFFF. aRd := aR at: ((i - 3 \\ 4) + 1). aR at: i+1 put: ((aRi - aKj - (aRa bitAnd: aRb) - (aRc bitAnd: aRd)) bitAnd: 16rFFFF). self j: self j - 1. ]. result := ByteArray new. aR do: [:a16BitWord | result := result, (a16BitWord asByteArrayOfSize: 2) ]. ^result. ! ----- Method: ARC2>>setKeySize (in category 'key') ----- setKeySize self T8: (self T1+7) // 8. self TM: (255 \\ (2 raisedTo: (8 + self T1 - (8 * self T8)))).! BlockCipher subclass: #Blowfish instanceVariableNames: 'rounds piArray s0 s1 s2 s3 xl xr current key data index' classVariableNames: '' poolDictionaries: '' category: 'CryptographyCiphers-Blowfish'! !Blowfish commentStamp: 'PaulDeBruicker 4/21/2011 12:00' prior: 0! This is just enough of the Blowfish algorithm from http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/lib/libc/crypt/blowfish.c to be able to run BCrypt. Instance Variables: rounds <AbstractSound | CalendarDuration | Collection | Color | DateAndTime | DhbDecimalFloatingNumber | DhbMatrix | DhbPolynomial | Duration | InfiniteDuration | Number | PassportNotAMetanumber | Point | ScientificDuration | TemporalInterval | Timespan | TraitComposition | TraitDescription | TraitTransformation> piArray <Object> s0 <Matrix> s1 <Object> s2 <Object> s3 <Object> s4 <ProtoObject | PseudoContext> xl <Integer> xr <Integer> current <Integer> key <ProtoObject | PseudoContext> data <Object>! ----- Method: Blowfish class>>blockSize (in category 'defaults') ----- blockSize ^8! ----- Method: Blowfish class>>decrypt:with: (in category 'decrypt') ----- decrypt: someData with: aKeyByteArray "use this when you have a wordArray" ^self new decrypt: someData with: aKeyByteArray.! ----- Method: Blowfish class>>decryptString:with: (in category 'decrypt') ----- decryptString: aString with: aKey | decryptedData | decryptedData := self new ecbDecrypt: aString asByteArray with: aKey asByteArray. ^ String fromByteArray: decryptedData asByteArray! ----- Method: Blowfish class>>decryptToString:with: (in category 'decrypt') ----- decryptToString: someData with: aKey "use this to decrypt to a String; drop any trailing null chars" |decryptedData | decryptedData := (self new ecbDecrypt: someData with: aKey asByteArray ). ^(String fromByteArray: decryptedData ) trimRight: [:ch| ch = Character null]! ----- Method: Blowfish class>>defaultRounds (in category 'defaults') ----- defaultRounds ^self minRounds! ----- Method: Blowfish class>>ecbDecrypt:with: (in category 'encrypt') ----- ecbDecrypt: someData with: aKey "use this when you have a byteArray" ^self new ecbDecrypt: someData with: aKey.! ----- Method: Blowfish class>>ecbEncrypt:with: (in category 'encrypt') ----- ecbEncrypt: someData with: aKey "use this when you have a byteArray" ^self new ecbEncrypt: someData with: aKey.! ----- Method: Blowfish class>>encrypt:with: (in category 'encrypt') ----- encrypt: someData with: aKey "use this when you have a wordArray" ^self new encrypt: someData with: aKey.! ----- Method: Blowfish class>>encryptString:with: (in category 'encrypt') ----- encryptString: someData with: aKeyString "use this to encrypt a string" |dataToEncrypt | dataToEncrypt := OrderedCollection streamContents: [:strm| someData do: [:each | strm nextPut: each asciiValue ] ]. ^self new ecbEncrypt: dataToEncrypt asArray with: aKeyString asByteArray! ----- Method: Blowfish class>>keySize (in category 'defaults') ----- keySize ^32! ----- Method: Blowfish class>>maxRounds (in category 'defaults') ----- maxRounds ^20 ! ----- Method: Blowfish class>>maxUserKeyLength (in category 'defaults') ----- maxUserKeyLength ^448/8! ----- Method: Blowfish class>>minRounds (in category 'defaults') ----- minRounds ^16! ----- Method: Blowfish class>>pBox (in category 'defaults') ----- pBox ^#( 16r243F6A88 16r85A308D3 16r13198A2E 16r03707344 16rA4093822 16r299F31D0 16r082EFA98 16rEC4E6C89 16r452821E6 16r38D01377 16rBE5466CF 16r34E90C6C 16rC0AC29B7 16rC97C50DD 16r3F84D5B5 16rB5470917 16r9216D5D9 16r8979FB1B)! ----- Method: Blowfish class>>s0Box (in category 'defaults') ----- s0Box ^#(16rD1310BA6 16r98DFB5AC 16r2FFD72DB 16rD01ADFB7 16rB8E1AFED 16r6A267E96 16rBA7C9045 16rF12C7F99 16r24A19947 16rB3916CF7 16r0801F2E2 16r858EFC16 16r636920D8 16r71574E69 16rA458FEA3 16rF4933D7E 16r0D95748F 16r728EB658 16r718BCD58 16r82154AEE 16r7B54A41D 16rC25A59B5 16r9C30D539 16r2AF26013 16rC5D1B023 16r286085F0 16rCA417918 16rB8DB38EF 16r8E79DCB0 16r603A180E 16r6C9E0E8B 16rB01E8A3E 16rD71577C1 16rBD314B27 16r78AF2FDA 16r55605C60 16rE65525F3 16rAA55AB94 16r57489862 16r63E81440 16r55CA396A 16r2AAB10B6 16rB4CC5C34 16r1141E8CE 16rA15486AF 16r7C72E993 16rB3EE1411 16r636FBC2A 16r2BA9C55D 16r741831F6 16rCE5C3E16 16r9B87931E 16rAFD6BA33 16r6C24CF5C 16r7A325381 16r28958677 16r3B8F4898 16r6B4BB9AF 16rC4BFE81B 16r66282193 16r61D809CC 16rFB21A991 16r487CAC60 16r5DEC8032 16rEF845D5D 16rE98575B1 16rDC262302 16rEB651B88 16r23893E81 16rD396ACC5 16r0F6D6FF3 16r83F44239 16r2E0B4482 16rA4842004 16r69C8F04A 16r9E1F9B5E 16r21C66842 16rF6E96C9A 16r670C9C61 16rABD388F0 16r6A51A0D2 16rD8542F68 16r960FA728 16rAB5133A3 16r6EEF0B6C 16r137A3BE4 16rBA3BF050 16r7EFB2A98 16rA1F1651D 16r39AF0176 16r66CA593E 16r82430E88 16r8CEE8619 16r456F9FB4 16r7D84A5C3 16r3B8B5EBE 16rE06F75D8 16r85C12073 16r401A449F 16r56C16AA6 16r4ED3AA62 16r363F7706 16r1BFEDF72 16r429B023D 16r37D0D724 16rD00A1248 16rDB0FEAD3 16r49F1C09B 16r075372C9 16r80991B7B 16r25D479D8 16rF6E8DEF7 16rE3FE501A 16rB6794C3B 16r976CE0BD 16r04C006BA 16rC1A94FB6 16r409F60C4 16r5E5C9EC2 16r196A2463 16r68FB6FAF 16r3E6C53B5 16r1339B2EB 16r3B52EC6F 16r6DFC511F 16r9B30952C 16rCC814544 16rAF5EBD09 16rBEE3D004 16rDE334AFD 16r660F2807 16r192E4BB3 16rC0CBA857 16r45C8740F 16rD20B5F39 16rB9D3FBDB 16r5579C0BD 16r1A60320A 16rD6A100C6 16r402C7279 16r679F25FE 16rFB1FA3CC 16r8EA5E9F8 16rDB3222F8 16r3C7516DF 16rFD616B15 16r2F501EC8 16rAD0552AB 16r323DB5FA 16rFD238760 16r53317B48 16r3E00DF82 16r9E5C57BB 16rCA6F8CA0 16r1A87562E 16rDF1769DB 16rD542A8F6 16r287EFFC3 16rAC6732C6 16r8C4F5573 16r695B27B0 16rBBCA58C8 16rE1FFA35D 16rB8F011A0 16r10FA3D98 16rFD2183B8 16r4AFCB56C 16r2DD1D35B 16r9A53E479 16rB6F84565 16rD28E49BC 16r4BFB9790 16rE1DDF2DA 16rA4CB7E33 16r62FB1341 16rCEE4C6E8 16rEF20CADA 16r36774C01 16rD07E9EFE 16r2BF11FB4 16r95DBDA4D 16rAE909198 16rEAAD8E71 16r6B93D5A0 16rD08ED1D0 16rAFC725E0 16r8E3C5B2F 16r8E7594B7 16r8FF6E2FB 16rF2122B64 16r8888B812 16r900DF01C 16r4FAD5EA0 16r688FC31C 16rD1CFF191 16rB3A8C1AD 16r2F2F2218 16rBE0E1777 16rEA752DFE 16r8B021FA1 16rE5A0CC0F 16rB56F74E8 16r18ACF3D6 16rCE89E299 16rB4A84FE0 16rFD13E0B7 16r7CC43B81 16rD2ADA8D9 16r165FA266 16r80957705 16r93CC7314 16r211A1477 16rE6AD2065 16r77B5FA86 16rC75442F5 16rFB9D35CF 16rEBCDAF0C 16r7B3E89A0 16rD6411BD3 16rAE1E7E49 16r00250E2D 16r2071B35E 16r226800BB 16r57B8E0AF 16r2464369B 16rF009B91E 16r5563911D 16r59DFA6AA 16r78C14389 16rD95A537F 16r207D5BA2 16r02E5B9C5 16r83260376 16r6295CFA9 16r11C81968 16r4E734A41 16rB3472DCA 16r7B14A94A 16r1B510052 16r9A532915 16rD60F573F 16rBC9BC6E4 16r2B60A476 16r81E67400 16r08BA6FB5 16r571BE91F 16rF296EC6B 16r2A0DD915 16rB6636521 16rE7B9F9B6 16rFF34052E 16rC5855664 16r53B02D5D 16rA99F8FA1 16r08BA4799 16r6E85076A )! ----- Method: Blowfish class>>s1Box (in category 'defaults') ----- s1Box ^#(16r4B7A70E9 16rB5B32944 16rDB75092E 16rC4192623 16rAD6EA6B0 16r49A7DF7D 16r9CEE60B8 16r8FEDB266 16rECAA8C71 16r699A17FF 16r5664526C 16rC2B19EE1 16r193602A5 16r75094C29 16rA0591340 16rE4183A3E 16r3F54989A 16r5B429D65 16r6B8FE4D6 16r99F73FD6 16rA1D29C07 16rEFE830F5 16r4D2D38E6 16rF0255DC1 16r4CDD2086 16r8470EB26 16r6382E9C6 16r021ECC5E 16r09686B3F 16r3EBAEFC9 16r3C971814 16r6B6A70A1 16r687F3584 16r52A0E286 16rB79C5305 16rAA500737 16r3E07841C 16r7FDEAE5C 16r8E7D44EC 16r5716F2B8 16rB03ADA37 16rF0500C0D 16rF01C1F04 16r0200B3FF 16rAE0CF51A 16r3CB574B2 16r25837A58 16rDC0921BD 16rD19113F9 16r7CA92FF6 16r94324773 16r22F54701 16r3AE5E581 16r37C2DADC 16rC8B57634 16r9AF3DDA7 16rA9446146 16r0FD0030E 16rECC8C73E 16rA4751E41 16rE238CD99 16r3BEA0E2F 16r3280BBA1 16r183EB331 16r4E548B38 16r4F6DB908 16r6F420D03 16rF60A04BF 16r2CB81290 16r24977C79 16r5679B072 16rBCAF89AF 16rDE9A771F 16rD9930810 16rB38BAE12 16rDCCF3F2E 16r5512721F 16r2E6B7124 16r501ADDE6 16r9F84CD87 16r7A584718 16r7408DA17 16rBC9F9ABC 16rE94B7D8C 16rEC7AEC3A 16rDB851DFA 16r63094366 16rC464C3D2 16rEF1C1847 16r3215D908 16rDD433B37 16r24C2BA16 16r12A14D43 16r2A65C451 16r50940002 16r133AE4DD 16r71DFF89E 16r10314E55 16r81AC77D6 16r5F11199B 16r043556F1 16rD7A3C76B 16r3C11183B 16r5924A509 16rF28FE6ED 16r97F1FBFA 16r9EBABF2C 16r1E153C6E 16r86E34570 16rEAE96FB1 16r860E5E0A 16r5A3E2AB3 16r771FE71C 16r4E3D06FA 16r2965DCB9 16r99E71D0F 16r803E89D6 16r5266C825 16r2E4CC978 16r9C10B36A 16rC6150EBA 16r94E2EA78 16rA5FC3C53 16r1E0A2DF4 16rF2F74EA7 16r361D2B3D 16r1939260F 16r19C27960 16r5223A708 16rF71312B6 16rEBADFE6E 16rEAC31F66 16rE3BC4595 16rA67BC883 16rB17F37D1 16r018CFF28 16rC332DDEF 16rBE6C5AA5 16r65582185 16r68AB9802 16rEECEA50F 16rDB2F953B 16r2AEF7DAD 16r5B6E2F84 16r1521B628 16r29076170 16rECDD4775 16r619F1510 16r13CCA830 16rEB61BD96 16r0334FE1E 16rAA0363CF 16rB5735C90 16r4C70A239 16rD59E9E0B 16rCBAADE14 16rEECC86BC 16r60622CA7 16r9CAB5CAB 16rB2F3846E 16r648B1EAF 16r19BDF0CA 16rA02369B9 16r655ABB50 16r40685A32 16r3C2AB4B3 16r319EE9D5 16rC021B8F7 16r9B540B19 16r875FA099 16r95F7997E 16r623D7DA8 16rF837889A 16r97E32D77 16r11ED935F 16r16681281 16r0E358829 16rC7E61FD6 16r96DEDFA1 16r7858BA99 16r57F584A5 16r1B227263 16r9B83C3FF 16r1AC24696 16rCDB30AEB 16r532E3054 16r8FD948E4 16r6DBC3128 16r58EBF2EF 16r34C6FFEA 16rFE28ED61 16rEE7C3C73 16r5D4A14D9 16rE864B7E3 16r42105D14 16r203E13E0 16r45EEE2B6 16rA3AAABEA 16rDB6C4F15 16rFACB4FD0 16rC742F442 16rEF6ABBB5 16r654F3B1D 16r41CD2105 16rD81E799E 16r86854DC7 16rE44B476A 16r3D816250 16rCF62A1F2 16r5B8D2646 16rFC8883A0 16rC1C7B6A3 16r7F1524C3 16r69CB7492 16r47848A0B 16r5692B285 16r095BBF00 16rAD19489D 16r1462B174 16r23820E00 16r58428D2A 16r0C55F5EA 16r1DADF43E 16r233F7061 16r3372F092 16r8D937E41 16rD65FECF1 16r6C223BDB 16r7CDE3759 16rCBEE7460 16r4085F2A7 16rCE77326E 16rA6078084 16r19F8509E 16rE8EFD855 16r61D99735 16rA969A7AA 16rC50C06C2 16r5A04ABFC 16r800BCADC 16r9E447A2E 16rC3453484 16rFDD56705 16r0E1E9EC9 16rDB73DBD3 16r105588CD 16r675FDA79 16rE3674340 16rC5C43465 16r713E38D8 16r3D28F89E 16rF16DFF20 16r153E21E7 16r8FB03D4A 16rE6E39F2B 16rDB83ADF7)! ----- Method: Blowfish class>>s2Box (in category 'defaults') ----- s2Box ^#(16rE93D5A68 16r948140F7 16rF64C261C 16r94692934 16r411520F7 16r7602D4F7 16rBCF46B2E 16rD4A20068 16rD4082471 16r3320F46A 16r43B7D4B7 16r500061AF 16r1E39F62E 16r97244546 16r14214F74 16rBF8B8840 16r4D95FC1D 16r96B591AF 16r70F4DDD3 16r66A02F45 16rBFBC09EC 16r03BD9785 16r7FAC6DD0 16r31CB8504 16r96EB27B3 16r55FD3941 16rDA2547E6 16rABCA0A9A 16r28507825 16r530429F4 16r0A2C86DA 16rE9B66DFB 16r68DC1462 16rD7486900 16r680EC0A4 16r27A18DEE 16r4F3FFEA2 16rE887AD8C 16rB58CE006 16r7AF4D6B6 16rAACE1E7C 16rD3375FEC 16rCE78A399 16r406B2A42 16r20FE9E35 16rD9F385B9 16rEE39D7AB 16r3B124E8B 16r1DC9FAF7 16r4B6D1856 16r26A36631 16rEAE397B2 16r3A6EFA74 16rDD5B4332 16r6841E7F7 16rCA7820FB 16rFB0AF54E 16rD8FEB397 16r454056AC 16rBA489527 16r55533A3A 16r20838D87 16rFE6BA9B7 16rD096954B 16r55A867BC 16rA1159A58 16rCCA92963 16r99E1DB33 16rA62A4A56 16r3F3125F9 16r5EF47E1C 16r9029317C 16rFDF8E802 16r04272F70 16r80BB155C 16r05282CE3 16r95C11548 16rE4C66D22 16r48C1133F 16rC70F86DC 16r07F9C9EE 16r41041F0F 16r404779A4 16r5D886E17 16r325F51EB 16rD59BC0D1 16rF2BCC18F 16r41113564 16r257B7834 16r602A9C60 16rDFF8E8A3 16r1F636C1B 16r0E12B4C2 16r02E1329E 16rAF664FD1 16rCAD18115 16r6B2395E0 16r333E92E1 16r3B240B62 16rEEBEB922 16r85B2A20E 16rE6BA0D99 16rDE720C8C 16r2DA2F728 16rD0127845 16r95B794FD 16r647D0862 16rE7CCF5F0 16r5449A36F 16r877D48FA 16rC39DFD27 16rF33E8D1E 16r0A476341 16r992EFF74 16r3A6F6EAB 16rF4F8FD37 16rA812DC60 16rA1EBDDF8 16r991BE14C 16rDB6E6B0D 16rC67B5510 16r6D672C37 16r2765D43B 16rDCD0E804 16rF1290DC7 16rCC00FFA3 16rB5390F92 16r690FED0B 16r667B9FFB 16rCEDB7D9C 16rA091CF0B 16rD9155EA3 16rBB132F88 16r515BAD24 16r7B9479BF 16r763BD6EB 16r37392EB3 16rCC115979 16r8026E297 16rF42E312D 16r6842ADA7 16rC66A2B3B 16r12754CCC 16r782EF11C 16r6A124237 16rB79251E7 16r06A1BBE6 16r4BFB6350 16r1A6B1018 16r11CAEDFA 16r3D25BDD8 16rE2E1C3C9 16r44421659 16r0A121386 16rD90CEC6E 16rD5ABEA2A 16r64AF674E 16rDA86A85F 16rBEBFE988 16r64E4C3FE 16r9DBC8057 16rF0F7C086 16r60787BF8 16r6003604D 16rD1FD8346 16rF6381FB0 16r7745AE04 16rD736FCCC 16r83426B33 16rF01EAB71 16rB0804187 16r3C005E5F 16r77A057BE 16rBDE8AE24 16r55464299 16rBF582E61 16r4E58F48F 16rF2DDFDA2 16rF474EF38 16r8789BDC2 16r5366F9C3 16rC8B38E74 16rB475F255 16r46FCD9B9 16r7AEB2661 16r8B1DDF84 16r846A0E79 16r915F95E2 16r466E598E 16r20B45770 16r8CD55591 16rC902DE4C 16rB90BACE1 16rBB8205D0 16r11A86248 16r7574A99E 16rB77F19B6 16rE0A9DC09 16r662D09A1 16rC4324633 16rE85A1F02 16r09F0BE8C 16r4A99A025 16r1D6EFE10 16r1AB93D1D 16r0BA5A4DF 16rA186F20F 16r2868F169 16rDCB7DA83 16r573906FE 16rA1E2CE9B 16r4FCD7F52 16r50115E01 16rA70683FA 16rA002B5C4 16r0DE6D027 16r9AF88C27 16r773F8641 16rC3604C06 16r61A806B5 16rF0177A28 16rC0F586E0 16r006058AA 16r30DC7D62 16r11E69ED7 16r2338EA63 16r53C2DD94 16rC2C21634 16rBBCBEE56 16r90BCB6DE 16rEBFC7DA1 16rCE591D76 16r6F05E409 16r4B7C0188 16r39720A3D 16r7C927C24 16r86E3725F 16r724D9DB9 16r1AC15BB4 16rD39EB8FC 16rED545578 16r08FCA5B5 16rD83D7CD3 16r4DAD0FC4 16r1E50EF5E 16rB161E6F8 16rA28514D9 16r6C51133C 16r6FD5C7E7 16r56E14EC4 16r362ABFCE 16rDDC6C837 16rD79A3234 16r92638212 16r670EFA8E 16r406000E0)! ----- Method: Blowfish class>>s3Box (in category 'defaults') ----- s3Box ^#(16r3A39CE37 16rD3FAF5CF 16rABC27737 16r5AC52D1B 16r5CB0679E 16r4FA33742 16rD3822740 16r99BC9BBE 16rD5118E9D 16rBF0F7315 16rD62D1C7E 16rC700C47B 16rB78C1B6B 16r21A19045 16rB26EB1BE 16r6A366EB4 16r5748AB2F 16rBC946E79 16rC6A376D2 16r6549C2C8 16r530FF8EE 16r468DDE7D 16rD5730A1D 16r4CD04DC6 16r2939BBDB 16rA9BA4650 16rAC9526E8 16rBE5EE304 16rA1FAD5F0 16r6A2D519A 16r63EF8CE2 16r9A86EE22 16rC089C2B8 16r43242EF6 16rA51E03AA 16r9CF2D0A4 16r83C061BA 16r9BE96A4D 16r8FE51550 16rBA645BD6 16r2826A2F9 16rA73A3AE1 16r4BA99586 16rEF5562E9 16rC72FEFD3 16rF752F7DA 16r3F046F69 16r77FA0A59 16r80E4A915 16r87B08601 16r9B09E6AD 16r3B3EE593 16rE990FD5A 16r9E34D797 16r2CF0B7D9 16r022B8B51 16r96D5AC3A 16r017DA67D 16rD1CF3ED6 16r7C7D2D28 16r1F9F25CF 16rADF2B89B 16r5AD6B472 16r5A88F54C 16rE029AC71 16rE019A5E6 16r47B0ACFD 16rED93FA9B 16rE8D3C48D 16r283B57CC 16rF8D56629 16r79132E28 16r785F0191 16rED756055 16rF7960E44 16rE3D35E8C 16r15056DD4 16r88F46DBA 16r03A16125 16r0564F0BD 16rC3EB9E15 16r3C9057A2 16r97271AEC 16rA93A072A 16r1B3F6D9B 16r1E6321F5 16rF59C66FB 16r26DCF319 16r7533D928 16rB155FDF5 16r03563482 16r8ABA3CBB 16r28517711 16rC20AD9F8 16rABCC5167 16rCCAD925F 16r4DE81751 16r3830DC8E 16r379D5862 16r9320F991 16rEA7A90C2 16rFB3E7BCE 16r5121CE64 16r774FBE32 16rA8B6E37E 16rC3293D46 16r48DE5369 16r6413E680 16rA2AE0810 16rDD6DB224 16r69852DFD 16r09072166 16rB39A460A 16r6445C0DD 16r586CDECF 16r1C20C8AE 16r5BBEF7DD 16r1B588D40 16rCCD2017F 16r6BB4E3BB 16rDDA26A7E 16r3A59FF45 16r3E350A44 16rBCB4CDD5 16r72EACEA8 16rFA6484BB 16r8D6612AE 16rBF3C6F47 16rD29BE463 16r542F5D9E 16rAEC2771B 16rF64E6370 16r740E0D8D 16rE75B1357 16rF8721671 16rAF537D5D 16r4040CB08 16r4EB4E2CC 16r34D2466A 16r0115AF84 16rE1B00428 16r95983A1D 16r06B89FB4 16rCE6EA048 16r6F3F3B82 16r3520AB82 16r011A1D4B 16r277227F8 16r611560B1 16rE7933FDC 16rBB3A792B 16r344525BD 16rA08839E1 16r51CE794B 16r2F32C9B7 16rA01FBAC9 16rE01CC87E 16rBCC7D1F6 16rCF0111C3 16rA1E8AAC7 16r1A908749 16rD44FBD9A 16rD0DADECB 16rD50ADA38 16r0339C32A 16rC6913667 16r8DF9317C 16rE0B12B4F 16rF79E59B7 16r43F5BB3A 16rF2D519FF 16r27D9459C 16rBF97222C 16r15E6FC2A 16r0F91FC71 16r9B941525 16rFAE59361 16rCEB69CEB 16rC2A86459 16r12BAA8D1 16rB6C1075E 16rE3056A0C 16r10D25065 16rCB03A442 16rE0EC6E0E 16r1698DB3B 16r4C98A0BE 16r3278E964 16r9F1F9532 16rE0D392DF 16rD3A0342B 16r8971F21E 16r1B0A7441 16r4BA3348C 16rC5BE7120 16rC37632D8 16rDF359F8D 16r9B992F2E 16rE60B6F47 16r0FE3F11D 16rE54CDA54 16r1EDAD891 16rCE6279CF 16rCD3E7E6F 16r1618B166 16rFD2C1D05 16r848FD2C5 16rF6FB2299 16rF523F357 16rA6327623 16r93A83531 16r56CCCD02 16rACF08162 16r5A75EBB5 16r6E163697 16r88D273CC 16rDE966292 16r81B949D0 16r4C50901B 16r71C65614 16rE6C6C7BD 16r327A140A 16r45E1D006 16rC3F27B9A 16rC9AA53FD 16r62A80F00 16rBB25BFE2 16r35BDD2F6 16r71126905 16rB2040222 16rB6CBCF7C 16rCD769C2B 16r53113EC0 16r1640E3D3 16r38ABBD60 16r2547ADF0 16rBA38209C 16rF746CE76 16r77AFA1C5 16r20756060 16r85CBFE4E 16r8AE88DD8 16r7AAAF9B0 16r4CF9AA7E 16r1948C25C 16r02FB8A8C 16r01C36AE4 16rD6EBE1F9 16r90D4F869 16rA65CDEA0 16r3F09252D 16rC208E69F 16rB74E6132 16rCE77E25B 16r578FDFE3 16r3AC372E6)! ----- Method: Blowfish>>blfDec:for: (in category 'private') ----- blfDec: dataArray for: blocks | j newDataArray | newDataArray := Array new: dataArray size. j := 1. (1 to: blocks) do: [ :each | xl := dataArray at: j. xr := dataArray at: j + 1. self decipher. newDataArray at: j put: xl. newDataArray at: j + 1 put: xr. j := j + 2 ]. ^ newDataArray! ----- Method: Blowfish>>blfEcbDecrypt: (in category 'private') ----- blfEcbDecrypt: dataArray | inStrm nullchar | inStrm := dataArray readStream. nullchar := 0. ^ByteArray streamContents: [:outStrm| [inStrm atEnd] whileFalse:[ xl:=((((inStrm next) bitShift: 24) bitOr: ((inStrm next ifNil:[nullchar]) bitShift: 16) )bitOr: ((inStrm next ifNil:[nullchar]) bitShift: 8)) bitOr: (inStrm next ifNil:[nullchar]). xr:=((((inStrm next ifNil:[nullchar]) bitShift: 24) bitOr: ((inStrm next ifNil:[nullchar]) bitShift: 16) )bitOr: ((inStrm next ifNil:[nullchar]) bitShift: 8)) bitOr: (inStrm next ifNil:[nullchar]). self decipher . outStrm nextPut: ((xl bitShift: -24) bitAnd: 16rff). outStrm nextPut: ((xl bitShift: -16) bitAnd: 16rff). outStrm nextPut: ((xl bitShift: -8) bitAnd: 16rff). outStrm nextPut: (xl bitAnd: 16rff). outStrm nextPut: ((xr bitShift: -24) bitAnd: 16rff). outStrm nextPut: ((xr bitShift: -16) bitAnd: 16rff). outStrm nextPut: ((xr bitShift: -8) bitAnd: 16rff). outStrm nextPut: (xr bitAnd: 16rff). ] ] ! ----- Method: Blowfish>>blfEcbEncrypt: (in category 'private') ----- blfEcbEncrypt: dataArray | inStrm nullchar | inStrm := dataArray readStream. nullchar := 0. ^ByteArray streamContents: [:outStrm| [inStrm atEnd] whileFalse:[ xl:=((((inStrm next) bitShift: 24) bitOr: ((inStrm next ifNil:[nullchar]) bitShift: 16) )bitOr: ((inStrm next ifNil:[nullchar]) bitShift: 8)) bitOr: (inStrm next ifNil:[nullchar]). xr:=((((inStrm next ifNil:[nullchar]) bitShift: 24) bitOr: ((inStrm next ifNil:[nullchar]) bitShift: 16) )bitOr: ((inStrm next ifNil:[nullchar]) bitShift: 8)) bitOr: (inStrm next ifNil:[nullchar]). self encipher . outStrm nextPut: ((xl bitShift: -24) bitAnd: 16rff). outStrm nextPut: ((xl bitShift: -16) bitAnd: 16rff). outStrm nextPut: ((xl bitShift: -8) bitAnd: 16rff). outStrm nextPut: (xl bitAnd: 16rff). outStrm nextPut: ((xr bitShift: -24) bitAnd: 16rff). outStrm nextPut: ((xr bitShift: -16) bitAnd: 16rff). outStrm nextPut: ((xr bitShift: -8) bitAnd: 16rff). outStrm nextPut: (xr bitAnd: 16rff). ] ]! ----- Method: Blowfish>>blfEnc:for: (in category 'private') ----- blfEnc: dataArray for: blocks | j newDataArray | newDataArray := dataArray copy. j := 1. (1 to: blocks) do: [ :each | xl := newDataArray at: j. xr := newDataArray at: j + 1. self encipher. newDataArray at: j put: xl. newDataArray at: j + 1 put: xr. j := j + 2 ]. ^ newDataArray! ----- Method: Blowfish>>blfKey: (in category 'private') ----- blfKey: aKey index:=0. key:= aKey. "self initializeLittleEndianBoxes." self initializeBoxes. self expandZeroState.! ----- Method: Blowfish>>calculateBlfRndFor:with:andPiAt: (in category 'private') ----- calculateBlfRndFor:oneHalf with: otherHalf andPiAt: n "#define BLFRND(s,p,i,j,n) (i ^= F(s,j) ^ (p)[n])" ^ oneHalf bitXor: ((self feistelWith: otherHalf ) bitXor: (piArray at: n)) . ! ----- Method: Blowfish>>decipher (in category 'private') ----- decipher | xL xR temp | xL := xl copy. xR := xr copy. xL := xL bitXor: (piArray at: 18). (17 to: 2 by: -2) do: [ :each | xR := self calculateBlfRndFor: xR with: xL andPiAt: each. xL := self calculateBlfRndFor: xL with: xR andPiAt: each - 1 ]. xl := xR bitXor: (piArray at: 1). xr := xL! ----- Method: Blowfish>>decrypt:with: (in category 'private') ----- decrypt: someData with: aKeyString self setRounds: self class defaultRounds . self blfKey: aKeyString. ^self blfDec: someData for: someData size // 2.! ----- Method: Blowfish>>decryptBlock: (in category 'accessing') ----- decryptBlock: cipherText | result | self setRounds: self class defaultRounds. self blfKey: key. result := self blfEcbDecrypt: cipherText. result withIndexDo: [:a :i | cipherText at: i put: a.]. ^cipherText ! ----- Method: Blowfish>>ecbDecrypt:with: (in category 'private') ----- ecbDecrypt: someData with: aKeyString self setRounds: self class defaultRounds . self blfKey: aKeyString. ^self blfEcbDecrypt: someData! ----- Method: Blowfish>>ecbEncrypt:with: (in category 'private') ----- ecbEncrypt: someData with: aKeyString self setRounds: self class defaultRounds . self blfKey: aKeyString. ^self blfEcbEncrypt: someData! ----- Method: Blowfish>>encipher (in category 'private') ----- encipher | xL xR temp | xL := xl copy. xR := xr copy. xL := xL bitXor: (piArray at: 1). " index <= 2 ifTrue: [ Transcript cr; show: 'New encipher'; cr; show: 'Left: '; show: xL hex greaseString ]." (2 to: 17 by: 2) do: [ :each | xR := self calculateBlfRndFor: xR with: xL andPiAt: each. xL := self calculateBlfRndFor: xL with: xR andPiAt: each + 1. " index = 2 ifTrue: [ Transcript cr; show: 'Right: '; show: xR hex greaseString; cr; show: 'Left: '; show: xL hex greaseString. index = 0 ] ]."]. xR := xR bitXor: (piArray at: 18). xl := xR. xr := xL! ----- Method: Blowfish>>encrypt:with: (in category 'private') ----- encrypt: someData with: aKeyString self setRounds: self class defaultRounds . self blfKey: aKeyString. ^self blfEnc: someData for: someData size // 2.! ----- Method: Blowfish>>encryptBlock: (in category 'accessing') ----- encryptBlock: plainText | result | self setRounds: self class defaultRounds. self blfKey: key. result := self blfEcbEncrypt: plainText. result withIndexDo: [:a :i | plainText at: i put: a.]. ^plainText! ----- Method: Blowfish>>expandZeroState (in category 'private') ----- expandZeroState | dataL dataR s0Test s1Test s2Test s3Test pTest| current := 1. pTest:=piArray copy. (1 to: rounds + 2) do: [ :each | piArray at: each put: ((piArray at: each) bitXor: (self stream2word: key)) ]. "xl := 16r0. xr := 16r0." xl:=#[0 0 0 0] unsignedLongAt: 1 bigEndian: true. xr:=#[0 0 0 0] unsignedLongAt: 1 bigEndian: true. pTest:=piArray copy. (1 to: rounds + 2 by: 2) do: [ :each | self encipher. piArray at: each put: xl copy. piArray at: each+1 put: xr copy.]. s0Test :=s0 copy. s1Test :=s1 copy. s2Test :=s2 copy. s3Test :=s3 copy. (1 to:256 by:2) do: [ :each | self encipher. s0 at: each put: xl copy. s0 at: each+1 put: xr copy. ]. (1 to:256 by:2) do: [ :each | self encipher. s1 at: each put: xl copy. s1 at: each+1 put: xr copy.]. (1 to:256 by:2) do: [ :each | self encipher. s2 at: each put: xl copy. s2 at: each+1 put: xr copy.]. (1 to:256 by:2) do: [ :each | self encipher. s3 at: each put: xl copy. s3 at: each+1 put: xr copy.]. " s0Test:= s0 select:[:each | each asByteArray size >4]. s1Test:= s1 select:[:each | each asByteArray size >4]. s2Test:= s2 select:[:each | each asByteArray size >4]. s3Test:= s3 select:[:each | each asByteArray size >4]. (s0Test size + s1Test size + s2Test size + s3Test size) >0 ifTrue:[self halt]."! ----- Method: Blowfish>>feistelWith: (in category 'private') ----- feistelWith: otherHalf | a b c d y byteArray | a := ((otherHalf bitShift: -24) bitAnd: 16rff) + 1. b := ((otherHalf bitShift: -16) bitAnd: 16rff) + 1. c := ((otherHalf bitShift: -8) bitAnd: 16rff) + 1. d := (otherHalf bitAnd: 16rff) + 1. y := ((s0 at: a) + (s1 at: b)) \\ 4294967296. " (2 raisedTo: 32)" y := y bitXor: (s2 at: c). y := (y + (s3 at: d)) \\ 4294967296. "(2 raisedTo: 32)" ^ y! ----- Method: Blowfish>>initializeBoxes (in category 'private') ----- initializeBoxes piArray :=self class pBox copy. s0:=self class s0Box copy. s1:=self class s1Box copy. s2:=self class s2Box copy. s3:=self class s3Box copy. ! ----- Method: Blowfish>>key: (in category 'accessing') ----- key: aByteArray self setRounds: self class defaultRounds . self blfKey: aByteArray. ! ----- Method: Blowfish>>setRounds: (in category 'private') ----- setRounds: anInteger rounds:=(anInteger >= self class minRounds and:[anInteger <= self class maxRounds]) ifTrue: [anInteger] ifFalse:[self class defaultRounds ] ! ----- Method: Blowfish>>stream2word: (in category 'private') ----- stream2word: someData |temp j dataBytes | temp:=0. dataBytes := someData size. 1 to: 4 do: [ :each | temp:=(temp bitShift: 8 ) bitOr: ((someData at: current) bitAnd: 16rFF). current := (current \\ dataBytes) +1. ]. ^temp. ! ----- Method: Blowfish>>stream2word:length: (in category 'private') ----- stream2word: someData length: someBytes |temp j | temp:=0. 1 to: 4 do: [ :each | temp:=(temp bitShift: 8 ) bitOr: ((someData atWrap: current) bitAnd: 16rFF). current := (current \\ someBytes) +1. ]. ^temp. ! BlockCipher subclass: #DES instanceVariableNames: 'cookedKey key encrypting nonPrimitive' classVariableNames: '' poolDictionaries: '' category: 'CryptographyCiphers-DES'! !DES commentStamp: '<historical>' prior: 0! This class implements the Data Encryption Standard (DES) block cipher per ANSI X3.92. It requires the presence of the 'DESPlugin'. At some future date the functionality of the plugin may be provided in pure Smalltalk, but the slowness would be prohibitive for anything other than trivial usage. The main barrier to translation is the heavy use of zero-based indexing of arrays. How to use: you first provide an 8-byte key which will be used to encode and decode the data. Internally, this is 'cooked' into a 32-word format to speed up the encryption process. The data is then sent in 8-byte packets to be encoded or decoded. You must externally account for padding. See the 'testing' category on the class side for examples. As of this date (1/26/2000), the U.S. Government has lifted many of the previous restrictions on the export of encryption software, but you should check before exporting anything including this code. Submitted by Duane Maxwell. ! ----- Method: DES class>>blockSize (in category 'accessing') ----- blockSize ^ 8! ----- Method: DES class>>keySize (in category 'accessing') ----- keySize ^ 8! ----- Method: DES>>decryptBlock: (in category 'accessing') ----- decryptBlock: aByteArray | int | self primPluginAvailable ifTrue: [ encrypting = false ifFalse: [self key: key encrypt: false]. ^self transform: aByteArray]. nonPrimitive isNil ifTrue: [ nonPrimitive := DESNonPrimitive new setKeyFromByteArray: key]. int := ((aByteArray unsignedLongAt: 1 bigEndian: true) bitShift: 32) + (aByteArray unsignedLongAt: 5 bigEndian: true). int := nonPrimitive decryptBlock: int. aByteArray unsignedLongAt: 1 put: (int bitShift: -32) bigEndian: true. aByteArray unsignedLongAt: 5 put: (int bitAnd: 16rFFFFFFFF) bigEndian: true! ----- Method: DES>>encryptBlock: (in category 'accessing') ----- encryptBlock: aByteArray | int | self primPluginAvailable ifTrue: [ encrypting = true ifFalse: [self key: key encrypt: true]. ^self transform: aByteArray]. nonPrimitive isNil ifTrue: [ nonPrimitive := DESNonPrimitive new setKeyFromByteArray: key]. int := ((aByteArray unsignedLongAt: 1 bigEndian: true) bitShift: 32) + (aByteArray unsignedLongAt: 5 bigEndian: true). int := nonPrimitive encryptBlock: int. aByteArray unsignedLongAt: 1 put: (int bitShift: -32) bigEndian: true. aByteArray unsignedLongAt: 5 put: (int bitAnd: 16rFFFFFFFF) bigEndian: true! ----- Method: DES>>key: (in category 'accessing') ----- key: aByteArray key := aByteArray. encrypting := nil. nonPrimitive := nil! ----- Method: DES>>key:encrypt: (in category 'private') ----- key: aByteArray encrypt: aBoolean encrypting := aBoolean. self primPluginAvailable ifFalse: [^self]. aByteArray size = 8 ifFalse: [self error: 'DES key must be 8 bytes']. cookedKey := WordArray new: 32. cookedKey atAllPut: 0. self primCookKey: aByteArray mode: (aBoolean ifTrue: [1] ifFalse: [0]) to: cookedKey! ----- Method: DES>>primCookKey:mode:to: (in category 'primitives') ----- primCookKey: aByteArray mode: flag to: cooked <primitive: 'primitiveDESCookKey' module: 'DESPlugin'> ^ self primitiveFailed ! ----- Method: DES>>primPluginAvailable (in category 'primitives') ----- primPluginAvailable <primitive: 'primitiveDESPluginAvailable' module: 'DESPlugin'> ^ false! ----- Method: DES>>primTransform:using: (in category 'primitives') ----- primTransform: aByteArray using: cooked <primitive: 'primitiveDESTransform' module: 'DESPlugin'> ^ self primitiveFailed! ----- Method: DES>>transform: (in category 'private') ----- transform: block self primPluginAvailable ifFalse: [self error: 'DES plugin missing']. cookedKey ifNil: [ self error: 'DES key not provided']. cookedKey size = 32 ifFalse: [ self error: 'DES cooked key damaged']. block size = 8 ifFalse: [ self error: 'DES block must be 8 bytes']. self primTransform: block using: cookedKey. ! BlockCipher subclass: #DESNonPrimitive instanceVariableNames: 'k' classVariableNames: 'EBitSelectionTable IIP IP P PC1 PC2 SBoxes' poolDictionaries: '' category: 'CryptographyCiphers-DES'! ----- Method: DESNonPrimitive class>>initSBox:from: (in category 'class initialization') ----- initSBox: index from: anArray "Initialization data is given in the same order order as in the spec, which is nonsense. This method reorders it to avoid reordering in the encryption/decryption process." "Validity test: (DESNonPrimitive new applyToSBoxes: 2r011101000101110101000111101000011100101101011101) = 2r00110100111001011010010110101001" | row col | SBoxes at: index put: ((0 to: 63) collect: [:i | row := i // 32 * 2 + (i \\ 2). col := i // 2 \\ 16. anArray at: row * 16 + col + 1])! ----- Method: DESNonPrimitive class>>initialize (in category 'class initialization') ----- initialize "DESNonPrimitive initialize" DESBitPermutation initialize. PC1 := DESBitPermutation fromDESBitIndexes: #( 57 49 41 33 25 17 9 1 58 50 42 34 26 18 10 2 59 51 43 35 27 19 11 3 60 52 44 36 63 55 47 39 31 23 15 7 62 54 46 38 30 22 14 6 61 53 45 37 29 21 13 5 28 20 12 4) sourceWidth: 64. PC2 := DESBitPermutation fromDESBitIndexes: #( 14 17 11 24 1 5 3 28 15 6 21 10 23 19 12 4 26 8 16 7 27 20 13 2 41 52 31 37 47 55 30 40 51 45 33 48 44 49 39 56 34 53 46 42 50 36 29 32) sourceWidth: 56. IP := DESBitPermutation fromDESBitIndexes: #( 58 50 42 34 26 18 10 2 60 52 44 36 28 20 12 4 62 54 46 38 30 22 14 6 64 56 48 40 32 24 16 8 57 49 41 33 25 17 9 1 59 51 43 35 27 19 11 3 61 53 45 37 29 21 13 5 63 55 47 39 31 23 15 7) sourceWidth: 64. IIP := DESBitPermutation fromDESBitIndexes: #( 40 8 48 16 56 24 64 32 39 7 47 15 55 23 63 31 38 6 46 14 54 22 62 30 37 5 45 13 53 21 61 29 36 4 44 12 52 20 60 28 35 3 43 11 51 19 59 27 34 2 42 10 50 18 58 26 33 1 41 9 49 17 57 25) sourceWidth: 64. EBitSelectionTable := DESBitPermutation fromDESBitIndexes: #( 32 1 2 3 4 5 4 5 6 7 8 9 8 9 10 11 12 13 12 13 14 15 16 17 16 17 18 19 20 21 20 21 22 23 24 25 24 25 26 27 28 29 28 29 30 31 32 1) sourceWidth: 32. P := DESBitPermutation fromDESBitIndexes: #( 16 7 20 21 29 12 28 17 1 15 23 26 5 18 31 10 2 8 24 14 32 27 3 9 19 13 30 6 22 11 4 25) sourceWidth: 32. SBoxes := Array new: 8. self initSBox: 1 from: #( 14 4 13 1 2 15 11 8 3 10 6 12 5 9 0 7 0 15 7 4 14 2 13 1 10 6 12 11 9 5 3 8 4 1 14 8 13 6 2 11 15 12 9 7 3 10 5 0 15 12 8 2 4 9 1 7 5 11 3 14 10 0 6 13). self initSBox: 2 from: #( 15 1 8 14 6 11 3 4 9 7 2 13 12 0 5 10 3 13 4 7 15 2 8 14 12 0 1 10 6 9 11 5 0 14 7 11 10 4 13 1 5 8 12 6 9 3 2 15 13 8 10 1 3 15 4 2 11 6 7 12 0 5 14 9). self initSBox: 3 from: #( 10 0 9 14 6 3 15 5 1 13 12 7 11 4 2 8 13 7 0 9 3 4 6 10 2 8 5 14 12 11 15 1 13 6 4 9 8 15 3 0 11 1 2 12 5 10 14 7 1 10 13 0 6 9 8 7 4 15 14 3 11 5 2 12). self initSBox: 4 from: #( 7 13 14 3 0 6 9 10 1 2 8 5 11 12 4 15 13 8 11 5 6 15 0 3 4 7 2 12 1 10 14 9 10 6 9 0 12 11 7 13 15 1 3 14 5 2 8 4 3 15 0 6 10 1 13 8 9 4 5 11 12 7 2 14). self initSBox: 5 from: #( 2 12 4 1 7 10 11 6 8 5 3 15 13 0 14 9 14 11 2 12 4 7 13 1 5 0 15 10 3 9 8 6 4 2 1 11 10 13 7 8 15 9 12 5 6 3 0 14 11 8 12 7 1 14 2 13 6 15 0 9 10 4 5 3). self initSBox: 6 from: #( 12 1 10 15 9 2 6 8 0 13 3 4 14 7 5 11 10 15 4 2 7 12 9 5 6 1 13 14 0 11 3 8 9 14 15 5 2 8 12 3 7 0 4 10 1 13 11 6 4 3 2 12 9 5 15 10 11 14 1 7 6 0 8 13). self initSBox: 7 from: #( 4 11 2 14 15 0 8 13 3 12 9 7 5 10 6 1 13 0 11 7 4 9 1 10 14 3 5 12 2 15 8 6 1 4 11 13 12 3 7 14 10 15 6 8 0 5 9 2 6 11 13 8 1 4 10 7 9 5 0 15 14 2 3 12). self initSBox: 8 from: #( 13 2 8 4 6 15 11 1 10 9 3 14 5 0 12 7 1 15 13 8 10 3 7 4 12 5 6 11 0 14 9 2 7 11 4 1 9 12 14 2 0 6 10 13 15 3 5 8 2 1 14 7 4 10 8 13 15 12 9 0 3 5 6 11)! ----- Method: DESNonPrimitive>>applyToSBoxes: (in category 'encryption/decryption') ----- applyToSBoxes: anInteger | result bits | result := 0. 1 to: 8 do: [:i | bits := (anInteger bitShift: i*6-48) bitAnd: 63. result := (result bitShift: 4) + ((SBoxes at: i) at: bits+1)]. ^result! ----- Method: DESNonPrimitive>>blockSize (in category 'encryption/decryption') ----- blockSize ^8! ----- Method: DESNonPrimitive>>coreProcess:forward: (in category 'encryption/decryption') ----- coreProcess: anInteger forward: aBoolean | rLast lLast rCurrent rXored rSBoxed rPermuted | lLast := anInteger bitShift: -32. rLast := anInteger bitAnd: 16rFFFFFFFF. 1 to: 16 do: [:i | rCurrent := EBitSelectionTable permute: rLast. rXored := rCurrent bitXor: (k at: (aBoolean ifTrue: [i] ifFalse: [17-i])). rSBoxed := self applyToSBoxes: rXored. rPermuted := P permute: rSBoxed. rCurrent := rPermuted bitXor: lLast. lLast := rLast. rLast := rCurrent]. ^lLast + (rLast bitShift: 32)! ----- Method: DESNonPrimitive>>decryptBlock: (in category 'encryption/decryption') ----- decryptBlock: anInteger | permuted encoded | permuted := IP permute: anInteger. encoded := self coreProcess: permuted forward: false. ^IIP permute: encoded! ----- Method: DESNonPrimitive>>encryptBlock: (in category 'encryption/decryption') ----- encryptBlock: anInteger | permuted encoded | permuted := IP permute: anInteger. encoded := self coreProcess: permuted forward: true. ^IIP permute: encoded! ----- Method: DESNonPrimitive>>keySize (in category 'encryption/decryption') ----- keySize ^8! ----- Method: DESNonPrimitive>>setKey: (in category 'initialize-release') ----- setKey: anInteger "anInteger is a 64-bit DES key" "DES new setKey: 2" | kCurrent mask28 rot l r | mask28 := 16rFFFFFFF. kCurrent := PC1 permute: anInteger. l := kCurrent bitShift: -28. r := kCurrent bitAnd: mask28. k := Array new: 16. 1 to: 16 do: [:i | rot := #(1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1) at: i. false ifTrue: [ l := (l bitShift: 0-rot) + (l bitShift: 28-rot) bitAnd: mask28. r := (r bitShift: 0-rot) + (r bitShift: 28-rot) bitAnd: mask28] ifFalse: [ l := (l bitShift: rot) + (l bitShift: rot - 28) bitAnd: mask28. r := (r bitShift: rot) + (r bitShift: rot - 28) bitAnd: mask28]. kCurrent := (l bitShift: 28) + r. k at: i put: (PC2 permute: kCurrent)]! ----- Method: DESNonPrimitive>>setKeyFromByteArray: (in category 'initialize-release') ----- setKeyFromByteArray: aByteArray self setKey: ((aByteArray unsignedLongAt: 1 bigEndian: true) bitShift: 32) + (aByteArray unsignedLongAt: 5 bigEndian: true)! BlockCipher subclass: #Rijndael instanceVariableNames: 'nB nK nR shiftOffset1 shiftOffset2 shiftOffset3 expandedKey eqExpandedKey state' classVariableNames: 'InvT0 InvT1 InvT2 InvT3 LogInverseTable LogTable RoundConstant SubByte SubByteInverse T0 T1 T2 T3' poolDictionaries: '' category: 'CryptographyCiphers-Rijndael'! ----- Method: Rijndael class>>blockSize (in category 'accessing') ----- blockSize "Rijndael supports variable block length. 128 bits is a good default." ^ 128 / 8! ----- Method: Rijndael class>>calculateInvTTables (in category 'class initialization') ----- calculateInvTTables | a t coef1 coef2 coef3 coef4 | InvT0 := Array new: 256. InvT1 := Array new: 256. InvT2 := Array new: 256. InvT3 := Array new: 256. coef1 := 14. coef2 := 9. coef3 := 13. coef4 := 11. 0 to: 255 do: [:avalue | a := self subByteInverse: avalue. t := ThirtyTwoBitRegister byte1: (self multiply: a by: coef1) byte2: (self multiply: a by: coef2) byte3: (self multiply: a by: coef3) byte4: (self multiply: a by: coef4). InvT0 at: avalue+1 put: t. t := t copy leftRotateBy: 24. InvT1 at: avalue+1 put: t. t := t copy leftRotateBy: 24. InvT2 at: avalue+1 put: t. t := t copy leftRotateBy: 24. InvT3 at: avalue+1 put: t. ]. ! ----- Method: Rijndael class>>calculateTTables (in category 'class initialization') ----- calculateTTables | a t coef1 coef2 coef3 coef4 | T0 := Array new: 256. T1 := Array new: 256. T2 := Array new: 256. T3 := Array new: 256. coef1 := 2. coef2 := 1. coef3 := 1. coef4 := 3. 0 to: 255 do: [:avalue | a := self subByte: avalue. t := ThirtyTwoBitRegister byte1: (self multiply: a by: coef1) byte2: (self multiply: a by: coef2) byte3: (self multiply: a by: coef3) byte4: (self multiply: a by: coef4). T0 at: avalue+1 put: t. t := t copy leftRotateBy: 24. T1 at: avalue+1 put: t. t := t copy leftRotateBy: 24. T2 at: avalue+1 put: t. t := t copy leftRotateBy: 24. T3 at: avalue+1 put: t. ]. ! ----- Method: Rijndael class>>initialize (in category 'class initialization') ----- initialize Smalltalk addToStartUpList: self. self startUp: false. self initializeLogTable. self initializeLogInverseTable. self initializeRoundConstant. self initializeSubByte. self initializeSubByteInverse. self calculateTTables. self calculateInvTTables. ! ----- Method: Rijndael class>>initializeLogInverseTable (in category 'class initialization') ----- initializeLogInverseTable LogInverseTable := #(1 3 5 15 17 51 85 255 26 46 114 150 161 248 19 53 95 225 56 72 216 115 149 164 247 2 6 10 30 34 102 170 229 52 92 228 55 89 235 38 106 190 217 112 144 171 230 49 83 245 4 12 20 60 68 204 79 209 104 184 211 110 178 205 76 212 103 169 224 59 77 215 98 166 241 8 24 40 120 136 131 158 185 208 107 189 220 127 129 152 179 206 73 219 118 154 181 196 87 249 16 48 80 240 11 29 39 105 187 214 97 163 254 25 43 125 135 146 173 236 47 113 147 174 233 32 96 160 251 22 58 78 210 109 183 194 93 231 50 86 250 21 63 65 195 94 226 61 71 201 64 192 91 237 44 116 156 191 218 117 159 186 213 100 172 239 42 126 130 157 188 223 122 142 137 128 155 182 193 88 232 35 101 175 234 37 111 177 200 67 197 84 252 31 33 99 165 244 7 9 27 45 119 153 176 203 70 202 69 207 74 222 121 139 134 145 168 227 62 66 198 81 243 14 18 54 90 238 41 123 141 140 143 138 133 148 167 242 13 23 57 75 221 124 132 151 162 253 28 36 108 180 199 82 246 1)! ----- Method: Rijndael class>>initializeLogTable (in category 'class initialization') ----- initializeLogTable LogTable := #(0 0 25 1 50 2 26 198 75 199 27 104 51 238 223 3 100 4 224 14 52 141 129 239 76 113 8 200 248 105 28 193 125 194 29 181 249 185 39 106 77 228 166 114 154 201 9 120 101 47 138 5 33 15 225 36 18 240 130 69 53 147 218 142 150 143 219 189 54 208 206 148 19 92 210 241 64 70 131 56 102 221 253 48 191 6 139 98 179 37 226 152 34 136 145 16 126 110 72 195 163 182 30 66 58 107 40 84 250 133 61 186 43 121 10 21 155 159 94 202 78 212 172 229 243 115 167 87 175 88 168 80 244 234 214 116 79 174 233 213 231 230 173 232 44 215 117 122 235 22 11 245 89 203 95 176 156 169 81 160 127 12 246 111 23 196 73 236 216 67 31 45 164 118 123 183 204 187 62 90 251 96 177 134 59 82 161 108 170 85 41 157 151 178 135 144 97 190 220 252 188 149 207 205 55 63 91 209 83 57 132 60 65 162 109 71 20 42 158 93 86 242 211 171 68 17 146 217 35 32 46 137 180 124 184 38 119 153 227 165 103 74 237 222 197 49 254 24 13 99 140 128 192 247 112 7)! ----- Method: Rijndael class>>initializeRoundConstant (in category 'class initialization') ----- initializeRoundConstant RoundConstant := #(1 2 4 8 16 32 64 128 27 54 108 216 171 77 154 47 94 188 99 198 151 53 106 212 179 125 250 239 197 145 57)! ----- Method: Rijndael class>>initializeSubByte (in category 'class initialization') ----- initializeSubByte SubByte := #(99 124 119 123 242 107 111 197 48 1 103 43 254 215 171 118 202 130 201 125 250 89 71 240 173 212 162 175 156 164 114 192 183 253 147 38 54 63 247 204 52 165 229 241 113 216 49 21 4 199 35 195 24 150 5 154 7 18 128 226 235 39 178 117 9 131 44 26 27 110 90 160 82 59 214 179 41 227 47 132 83 209 0 237 32 252 177 91 106 203 190 57 74 76 88 207 208 239 170 251 67 77 51 133 69 249 2 127 80 60 159 168 81 163 64 143 146 157 56 245 188 182 218 33 16 255 243 210 205 12 19 236 95 151 68 23 196 167 126 61 100 93 25 115 96 129 79 220 34 42 144 136 70 238 184 20 222 94 11 219 224 50 58 10 73 6 36 92 194 211 172 98 145 149 228 121 231 200 55 109 141 213 78 169 108 86 244 234 101 122 174 8 186 120 37 46 28 166 180 198 232 221 116 31 75 189 139 138 112 62 181 102 72 3 246 14 97 53 87 185 134 193 29 158 225 248 152 17 105 217 142 148 155 30 135 233 206 85 40 223 140 161 137 13 191 230 66 104 65 153 45 15 176 84 187 22)! ----- Method: Rijndael class>>initializeSubByteInverse (in category 'class initialization') ----- initializeSubByteInverse SubByteInverse := #(82 9 106 213 48 54 165 56 191 64 163 158 129 243 215 251 124 227 57 130 155 47 255 135 52 142 67 68 196 222 233 203 84 123 148 50 166 194 35 61 238 76 149 11 66 250 195 78 8 46 161 102 40 217 36 178 118 91 162 73 109 139 209 37 114 248 246 100 134 104 152 22 212 164 92 204 93 101 182 146 108 112 72 80 253 237 185 218 94 21 70 87 167 141 157 132 144 216 171 0 140 188 211 10 247 228 88 5 184 179 69 6 208 44 30 143 202 63 15 2 193 175 189 3 1 19 138 107 58 145 17 65 79 103 220 234 151 242 207 206 240 180 230 115 150 172 116 34 231 173 53 133 226 249 55 232 28 117 223 110 71 241 26 113 29 41 197 137 111 183 98 14 170 24 190 27 252 86 62 75 198 210 121 32 154 219 192 254 120 205 90 244 31 221 168 51 136 7 199 49 177 18 16 89 39 128 236 95 96 81 127 169 25 181 74 13 45 229 122 159 147 201 156 239 160 224 59 77 174 42 245 176 200 235 187 60 131 83 153 97 23 43 4 126 186 119 214 38 225 105 20 99 85 33 12 125)! ----- Method: Rijndael class>>keySize (in category 'accessing') ----- keySize "Rijndael supports variable key length. 256 bits is a good default." ^ 256 / 8! ----- Method: Rijndael class>>multiply:by: (in category 'byte functions') ----- multiply: value1 by: value2 (value1 = 0 or: [value2 = 0]) ifTrue: [^ 0]. ^ LogInverseTable at: ((LogTable at: value1 + 1) + (LogTable at: value2 + 1) \\ 255 + 1)! ----- Method: Rijndael class>>new (in category 'instance creation') ----- new ^ super new keySize: self keySize; blockSize: self blockSize! ----- Method: Rijndael class>>startUp: (in category 'class initialization') ----- startUp: bool [ (Smalltalk classNamed: #Rijndael) ifNotNil: [ :rijndaelClass | rijndaelClass classPool at: #T0 ifPresent: [ :t0 | t0 ifNotNil: [ Rijndael calculateTTables ] ]. rijndaelClass classPool at: #InvT0 ifPresent: [ :invT0 | invT0 ifNotNil: [ Rijndael calculateInvTTables ] ] ] ] ifError: [ "ignore" ]! ----- Method: Rijndael class>>subByte: (in category 'byte functions') ----- subByte: index ^ SubByte at: index+1! ----- Method: Rijndael class>>subByteInverse: (in category 'byte functions') ----- subByteInverse: index ^ SubByteInverse at: index+1! ----- Method: Rijndael>>addEqRoundKey: (in category 'block cipher') ----- addEqRoundKey: roundNumber | start | start := roundNumber * nB. 1 to: nB do: [:k | (state at: k) bitXor: (eqExpandedKey at: start + k)]! ----- Method: Rijndael>>addRoundKey: (in category 'block cipher') ----- addRoundKey: roundNumber | start | start := roundNumber * nB. 1 to: nB do: [:k | (state at: k) bitXor: (expandedKey at: start + k)]! ----- Method: Rijndael>>blockSize (in category 'accessing') ----- blockSize ^ nB * 32 / 8! ----- Method: Rijndael>>blockSize: (in category 'accessing') ----- blockSize: anInteger nB := anInteger * 8 / 32! ----- Method: Rijndael>>calculateNumberOfRounds (in category 'setup') ----- calculateNumberOfRounds nK = 4 ifTrue: [ nB = 4 ifTrue: [nR := 10]. nB = 6 ifTrue: [nR := 12]. nB = 8 ifTrue: [nR := 14]]. nK = 6 ifTrue: [ nB = 4 ifTrue: [nR := 12]. nB = 6 ifTrue: [nR := 12]. nB = 8 ifTrue: [nR := 14]]. nK = 8 ifTrue: [ nB = 4 ifTrue: [nR := 14]. nB = 6 ifTrue: [nR := 14]. nB = 8 ifTrue: [nR := 14]]. ! ----- Method: Rijndael>>calculateShiftOffsets (in category 'setup') ----- calculateShiftOffsets (nB = 4 or: [nB = 6]) ifTrue: [shiftOffset1 := 1. shiftOffset2 := 2. shiftOffset3 := 3]. nB = 8 ifTrue: [shiftOffset1 := 1. shiftOffset2 := 3. shiftOffset3 := 4]! ----- Method: Rijndael>>decryptBlock: (in category 'accessing') ----- decryptBlock: aByteArray state := self stateFromBytes: aByteArray. self decryptState: state. self storeState: state into: aByteArray! ----- Method: Rijndael>>decryptState: (in category 'block cipher') ----- decryptState: aState state := aState. self addEqRoundKey: nR. nR - 1 to: 1 by: -1 do: [:roundNumber | self eqRound: roundNumber]. self eqFinalRound: 0. ^ state! ----- Method: Rijndael>>encryptBlock: (in category 'accessing') ----- encryptBlock: aByteArray state := self stateFromBytes: aByteArray. self encryptState: state. self storeState: state into: aByteArray! ----- Method: Rijndael>>encryptState: (in category 'block cipher') ----- encryptState: aState state := aState. self addRoundKey: 0. 1 to: nR - 1 do: [:roundNumber | self round: roundNumber]. self finalRound: nR. ^ state! ----- Method: Rijndael>>eqExpandKey (in category 'key schedule') ----- eqExpandKey eqExpandedKey := Array new: nB * (nR + 1). 1 to: nB do: [:j | eqExpandedKey at: 0*nB + j put: (expandedKey at: 0*nB + j). eqExpandedKey at: nR*nB + j put: (expandedKey at: nR*nB + j). ]. 1 to: nR-1 do: [:i | 1 to: nB do: [:j | eqExpandedKey at: i*nB + j put: (self invMixColumn: (expandedKey at: i*nB + j)) ] ]. ! ----- Method: Rijndael>>eqFinalRound: (in category 'block cipher') ----- eqFinalRound: roundNumber | a1 a2 a3 a4 newState start | newState := Array new: nB. "do SubBytesInverse and ShiftRowsInverse in one step" 0 to: nB-1 do: [:j | a1 := SubByteInverse at: ((state at: j + 1) byteAt: 1) + 1. a2 := SubByteInverse at: ((state at: (j - shiftOffset1) \\ nB + 1) byteAt: 2) + 1. a3 := SubByteInverse at: ((state at: (j - shiftOffset2) \\ nB + 1) byteAt: 3) + 1. a4 := SubByteInverse at: ((state at: (j - shiftOffset3) \\ nB + 1) byteAt: 4) + 1. newState at: j+1 put: (ThirtyTwoBitRegister byte1: a1 byte2: a2 byte3: a3 byte4: a4)]. "add equivalent round key" start := roundNumber * nB. 1 to: nB do: [:k | state at: k put: ((newState at: k) bitXor: (eqExpandedKey at: start + k))]! ----- Method: Rijndael>>eqRound: (in category 'block cipher') ----- eqRound: roundNumber | a0 a1 a2 a3 result newState start | newState := Array new: nB. "do SubBytesInverse, ShiftRowsInverse and MixColumnsInverse in one step" 0 to: nB-1 do: [:j | a0 := (state at: j + 1) byteAt: 1. a1 := (state at: (j - shiftOffset1) \\ nB + 1) byteAt: 2. a2 := (state at: (j - shiftOffset2) \\ nB + 1) byteAt: 3. a3 := (state at: (j - shiftOffset3) \\ nB + 1) byteAt: 4. result := (InvT0 at: a0+1) copy. result bitXor: (InvT1 at: a1+1). result bitXor: (InvT2 at: a2+1). result bitXor: (InvT3 at: a3+1). newState at: j+1 put: result]. "add equivalent round key" start := roundNumber * nB. 1 to: nB do: [:k | state at: k put: ((newState at: k) bitXor: (eqExpandedKey at: start + k))]! ----- Method: Rijndael>>example (in category 'examples') ----- example | k pt | k := #(16r2B 16r7E 16r15 16r16 16r28 16rAE 16rD2 16rA6 16rAB 16rF7 16r15 16r88 16r09 16rCF 16r4F 16r3C). pt := #(16r32 16r43 16rF6 16rA8 16r88 16r5A 16r30 16r8D 16r31 16r31 16r98 16rA2 16rE0 16r37 16r07 16r34). k := #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0). pt := #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0). pt := self stateFromBytes: pt. self key: k. 3 timesRepeat: [Transcript show: pt; cr. self encryptState: pt]. 3 timesRepeat: [Transcript show: pt; cr. self decryptState: pt]. Transcript show: pt; cr.! ----- Method: Rijndael>>example2 (in category 'examples') ----- example2 | k pt r | k := #(16r2B 16r7E 16r15 16r16 16r28 16rAE 16rD2 16rA6 16rAB 16rF7 16r15 16r88 16r09 16rCF 16r4F 16r3C). pt := #(16r32 16r43 16rF6 16rA8 16r88 16r5A 16r30 16r8D 16r31 16r31 16r98 16rA2 16rE0 16r37 16r07 16r34). pt := self stateFromBytes: pt. self key: k. r := Time millisecondsToRun: [10000 timesRepeat: [self encryptState: pt]]. ^ r ! ----- Method: Rijndael>>example3 (in category 'examples') ----- example3 | k pt | k := #(16r2B 16r7E 16r15 16r16 16r28 16rAE 16rD2 16rA6 16rAB 16rF7 16r15 16r88 16r09 16rCF 16r4F 16r3C) asByteArray. pt := #(16r32 16r43 16rF6 16rA8 16r88 16r5A 16r30 16r8D 16r31 16r31 16r98 16rA2 16rE0 16r37 16r07 16r34) asByteArray. self key: k. Transcript cr; show: pt hex. self encryptBlock: pt. Transcript cr; show: pt hex. self decryptBlock: pt. Transcript cr; show: pt hex! ----- Method: Rijndael>>expandKey: (in category 'key schedule') ----- expandKey: aByteArray | w total want sw key | key := self stateFromBytes: aByteArray columns: nK. total := nB * (nR + 1). w := Array new: total. 1 to: nK do: [:n | w at: n put: (key at: n)]. nK + 1 to: total do: [:n | want := (w at: n - 1) copy. (n - 1 \\ nK) = 0 ifTrue: [sw := ByteArray new: 4. sw at: 1 put: ((SubByte at: (want byteAt: 2) + 1) bitXor: (RoundConstant at: n-1 / nK)). 2 to: 4 do: [:i | sw at: i put: (SubByte at: (want byteAt: i \\ 4 + 1) + 1)]. sw := ThirtyTwoBitRegister loadFrom: sw at: 1] ifFalse: [(n - 1 \\ nK = 4) & (nK > 6) ifTrue: [sw := ByteArray new: 4. 1 to: 4 do: [:i | sw at: i put: (SubByte at: (want byteAt: i) + 1)]. sw := ThirtyTwoBitRegister loadFrom: sw at: 1] ifFalse: [sw := want] ]. w at: n put: ((w at: n - nK) copy bitXor: sw). ]. expandedKey := w! ----- Method: Rijndael>>finalRound: (in category 'block cipher') ----- finalRound: roundNumber | a1 a2 a3 a4 newState start | newState := Array new: nB. "do SubBytes and ShiftRows in one step" 0 to: nB-1 do: [:j | a1 := SubByte at: ((state at: j + 1) byteAt: 1) + 1. a2 := SubByte at: ((state at: (j + shiftOffset1) \\ nB + 1) byteAt: 2) + 1. a3 := SubByte at: ((state at: (j + shiftOffset2) \\ nB + 1) byteAt: 3) + 1. a4 := SubByte at: ((state at: (j + shiftOffset3) \\ nB + 1) byteAt: 4) + 1. newState at: j+1 put: (ThirtyTwoBitRegister byte1: a1 byte2: a2 byte3: a3 byte4: a4)]. "add round key" start := roundNumber * nB. 1 to: nB do: [:k | state at: k put: ((newState at: k) bitXor: (expandedKey at: start + k))]! ----- Method: Rijndael>>invMixColumn: (in category 'key schedule') ----- invMixColumn: aColumn | a0 a1 a2 a3 result | a0 := SubByte at: (aColumn byteAt: 1) + 1. a1 := SubByte at: (aColumn byteAt: 2) + 1. a2 := SubByte at: (aColumn byteAt: 3) + 1. a3 := SubByte at: (aColumn byteAt: 4) + 1. result := (InvT0 at: a0+1) copy. result bitXor: (InvT1 at: a1+1). result bitXor: (InvT2 at: a2+1). result bitXor: (InvT3 at: a3+1). ^ result ! ----- Method: Rijndael>>key: (in category 'accessing') ----- key: aByteArray " nK := aByteArray size * 8 / 32." self setSystem. self expandKey: aByteArray. self eqExpandKey! ----- Method: Rijndael>>keySize (in category 'accessing') ----- keySize ^ nK * 32 / 8! ----- Method: Rijndael>>keySize: (in category 'accessing') ----- keySize: anInteger nK := anInteger * 8 / 32! ----- Method: Rijndael>>round: (in category 'block cipher') ----- round: roundNumber | a0 a1 a2 a3 result newState start | newState := Array new: nB. "do SubBytes, ShiftRows and MixColumns in one step" 0 to: nB-1 do: [:j | a0 := (state at: j + 1) byteAt: 1. a1 := (state at: (j + shiftOffset1) \\ nB + 1) byteAt: 2. a2 := (state at: (j + shiftOffset2) \\ nB + 1) byteAt: 3. a3 := (state at: (j + shiftOffset3) \\ nB + 1) byteAt: 4. result := (T0 at: a0+1) copy. result bitXor: (T1 at: a1+1). result bitXor: (T2 at: a2+1). result bitXor: (T3 at: a3+1). newState at: j+1 put: result]. "add round key" start := roundNumber * nB. 1 to: nB do: [:k | state at: k put: ((newState at: k) bitXor: (expandedKey at: start + k))]! ----- Method: Rijndael>>setSystem (in category 'setup') ----- setSystem self calculateNumberOfRounds. self calculateShiftOffsets. ! ----- Method: Rijndael>>stateFromBytes: (in category 'setup') ----- stateFromBytes: aByteArray ^ self stateFromBytes: aByteArray columns: nB ! ----- Method: Rijndael>>stateFromBytes:columns: (in category 'setup') ----- stateFromBytes: aByteArray columns: numberOfColumns aByteArray size = (4 * numberOfColumns) ifFalse: [^ self error: 'wrong block size']. ^ (1 to: numberOfColumns) collect: [:k | ThirtyTwoBitRegister loadFrom: aByteArray at: (k-1)*4 + 1]! ----- Method: Rijndael>>storeState:into: (in category 'setup') ----- storeState: anArray into: aByteArray anArray withIndexDo: [ :register :k | register storeInto: aByteArray at: (k-1)*4 + 1]! BlockCipher subclass: #TripleDES instanceVariableNames: 'des1 des2 des3' classVariableNames: '' poolDictionaries: '' category: 'CryptographyCiphers-DES'! ----- Method: TripleDES class>>blockSize (in category 'accessing') ----- blockSize ^ 8! ----- Method: TripleDES class>>keySize (in category 'accessing') ----- keySize ^ 8*3! ----- Method: TripleDES class>>new (in category 'instance creation') ----- new ^ super new initialize! ----- Method: TripleDES>>decryptBlock: (in category 'accessing') ----- decryptBlock: plainText des3 decryptBlock: plainText. des2 encryptBlock: plainText. des1 decryptBlock: plainText! ----- Method: TripleDES>>encryptBlock: (in category 'accessing') ----- encryptBlock: plainText des1 encryptBlock: plainText. des2 decryptBlock: plainText. des3 encryptBlock: plainText! ----- Method: TripleDES>>initialize (in category 'accessing') ----- initialize des1 := DES new. des2 := DES new. des3 := DES new! ----- Method: TripleDES>>key: (in category 'accessing') ----- key: aByteArray des1 key: (aByteArray copyFrom: 1 to: 8). des2 key: (aByteArray copyFrom: 9 to: 16). des3 key: (aByteArray copyFrom: 17 to: 24)! ----- Method: BlockCipherMode class>>key: (in category '*cryptographyciphers') ----- key: aByteArray Warning signal: 'you do NOT want to use this method in a real program because we use a hard-coded nonce. You should take care of your own nonce.'. ^ (self on: (Rijndael new keySize: aByteArray size; key: aByteArray)) initialVector: #(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16) asByteArray! ----- Method: PKCS5Or7PaddingMode class>>key: (in category '*cryptographyciphers') ----- key: aByteArray Warning signal: 'you do NOT want to use this method in a real program because we use a hard-coded nonce. You should take care of your own nonce.'. ^ (self on: (Rijndael new keySize: aByteArray size; key: aByteArray)) " initialVector: #(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16) asByteArray"! |
Free forum by Nabble | Edit this page |