[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
|