[squeak-dev] The Inbox: CryptographyCiphers-tpr.21.mcz

commits at source.squeak.org commits at source.squeak.org
Thu May 28 23:00:54 UTC 2020


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 * Ron at USMedRec.com

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 * Ron at USMedRec.com

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: rsa-labs at rsa.com

















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 * Ron at USMedRec.com

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"!



More information about the Squeak-dev mailing list