'From Squeak3.8 of ''5 May 2005'' [latest update: #6665] on 7 November 2005 at 6:43:18 pm'! ReadWriteStream subclass: #EncryptedStream instanceVariableNames: 'ncryptor stream' classVariableNames: '' poolDictionaries: '' category: 'Spoon-Security'! Object subclass: #MessageDigest instanceVariableNames: '' classVariableNames: 'Padding' poolDictionaries: '' category: 'Spoon-Crypto'! !MessageDigest commentStamp: '' prior: 0! MessageDigest is the abstract superclass for the concrete message digest implementations. Message Digest Codes (aka Cryptographic Hash Functions) compute a seemingly unpredictable, fixed length "hash" from arbitrary input. They're used as building blocks for other algorithms including digital signature, message authentication code (MAC), Pseudo Random Number Generators (PRNG) and password based encryption algorithms. Message Digest Codes are also used to "hash passwords" and as part of the ubiquitous SSL/TLS protocol suite. They're sort of like the "sonic screwdriver" of the crypto world. Note that this class simply computes hashes based on strings of input bytes. That is, we take a fixed array of values that we assume are bytes (i.e. - integral values between 0 and 255 inclusive) and operate directly on them. Keep this in mind as you start playing with Unicode and any other representation that can use more than one byte for a single character. The tests in the Crypto-Test SUnit test suite are useful in understanding how these classes work. But since I tend to cringe anytime anyone else says their code is "self documenting," I should probably put my money where my mouth is and say a few things about using these classes. Message Digest Functions Cryptographic Hash Functions are implemented as subclasses of the MessageDigest class. This class encapsulates some common behavior inherited by all it's subclasses. There are four protocols used by the MessageDigest subclasses: digesting, output size, private, and sensitive data. (Actually, the sensitive data protocol is implemented by the MessageDigest class, but as it's an abstract super class, it depends on subclasses to actually express the protocol's behavior.) instance creation If you want to produce a cryptographic hash, then the first step is to create an instance of a message digest object. For example, let's see how we would create an instance of a SHA1 message digest object. | a | a _ SHA1 new. digesting protocol Now that we have a SHA1 instance, let's start digesting something. We do this with the update: message. We can call the update: function as many times as needed. Note that the MessageDigest subclasses are designed to take ByteArray's. a update: ('this is a test' asByteArray). a update: ('here is some more text to be hashed' asByteArray). To produce a message digest, use the digest message. The digest message returns a ByteArray containing the message digest. | b | b _ a digest. If you have an existing array, you can tell a MessageDigest object to put a digest into it with the digest: at: message. The first parameter to this message is an existing array, while the second parameter is an index into the array where you want the digest to go. The following example puts a message digest in elements 12 through 32 in the byte array b. | b | b _ ByteArray new: 50. a digest: b at: 12. After creating a message digest, you may want to create another digest for another data stream. You can do this using the same MessageDigest object, but you must call the reinitialize message first. a reinitialize. output size protocol Not all hash functions produce the same sized output. If you want to know how large the output a particular function will produce, you can use the outputSize message. It responds with an integer that is the size a buffer would have to be to hold it's output. The digest message uses this function to create a byte array to hold the digest it returns: |rv| rv _ ByteArray new: (a outputSize). Code archeologists will note that there is an outputSize message that takes an integer as a parameter. This is designed mostly for encipherment algorithms where the output size is not fixed. For consistency, the message is replicated in the MessageDigest classes and does pretty much the same thing as the plain ol' outputSize message. sensitive data protocol One way that attackers can recover sensitive information is by looking at swap files, or live memory heaps. In an ideal world they wouldn't be able to get any information from looking at these sorts of things, but in the real world we have to worry about these corner cases. The clearSensitiveData protocol zeroizes any sensitive information stored in the class' instance variables. You should do this after using a message digest object and before the object falls out of scope. a clearSensitiveData private protocol The private protocol is.. uh... private. You are, of course, allowed and encouraged to examine how we actually produce our message digests, but we should warn you that there's still some refactoring left to be done on the MessageDigest subclasses, so don't say we didn't warn you!!! MessageDigest subclass: #MD2 instanceVariableNames: 'checksum count state' classVariableNames: 'MD2Padding Sbox' poolDictionaries: '' category: 'Spoon-Crypto'! !MD2 commentStamp: '' prior: 0! This class is provided for reverse compatibility. Do not use MD2 in new applications. MD2 is a message digest code invented by Ron Rivest of MIT and RSA Data Security fame. This implementation is taken from the description of the algorithm provided in RFC 1319 (available at the IETF web page at http://www.ietf.org/rfc/rfc1319.txt). MD2 is not recommended for use with new projects. It is included here only to support an old Verisign Certificate that uses MD2 with RSA for digital signature production. New implementations should use SHA1 or SHA256. This class implements three implementation variables and two class variables. * Sbox (class variable) -- This is the substitution table used to create the digest. * MD2Padding (class variable) -- The last 16 byte block of a message is padded to include n bytes of value n. This is an array of arrays that contain those n n bytes. * checksum -- as part of the creation of the message digest, a "checksum" is generated. This variable contains the checksum for all bytes hashed at any given point. * count -- this integer contains the number of bytes input into the hash algorithm modulo 16. * state -- this 48 byte buffer is loaded with 16 bytes at a time, then "transformed" using the algorithm defined in RFC 1319. ! MessageDigest subclass: #MD4 instanceVariableNames: 'bitCount byteBuffer byteCount state savedState wordBuffer' classVariableNames: '' poolDictionaries: '' category: 'Spoon-Crypto'! !MD4 commentStamp: '' prior: 0! This class is provided for reverse compatibility reasons only. Do not use MD4 for new applications. MD4 is one of a series of hash functions invented by Ron Rivest of MIT. The algorithm has been published widely; this implementation comes from IETF RFC 1320 ( available at http://www.ietf.org/rfc/rfc1320.txt .) RSA Labs ( the research arm of the commercial venture launched by Dr. Rivest ) has a nice FAQ entry in their RSA Labs FAQ at http://www.rsasecurity.com/rsalabs/node.asp?id=2253 . From this, we learn that attacks on MD4 were developed in the early and mid 90's. The most important line from this page is probably, "Clearly, MD4 should now be considered broken." ! MessageDigest subclass: #MD5 instanceVariableNames: 'bitCount byteBuffer byteCount state savedState wordBuffer' classVariableNames: 'T' poolDictionaries: '' category: 'Spoon-Crypto'! !MD5 commentStamp: '' prior: 0! This implementation is provided for reverse compatibility reasons only. Do not use MD5 for new applications.! Object subclass: #PasswordBasedEncryptor instanceVariableNames: 'salt iteration password' classVariableNames: '' poolDictionaries: '' category: 'Spoon-Crypto'! !PasswordBasedEncryptor commentStamp: '' prior: 0! This class derives encryption or message authentication keys from passwords according to the alogrithm(s) provided in PKCS#5 v2.0. The PKCS#5 spec describes two functions whose inputs are a password, a salt, and an iteration count and whose output is a "derived key." The two functions: PBKDF1 and PBKDF2 are implemented as messages to an instance of this class. The former is recommended only for compatibility with previous applications while the latter is recommended for new applications. Like other classes in this package, after you have used it, send it the #clearSensitiveData message to erase remnants of sensitive bits of data (like the password). Here's an example of the use of this function: | encryptionKey pbe | pbe _ ( PasswordBasedEncryptor new ) password: 'you can have a very long passphrase if you like'; salt: #( 8 3 4 2 5 6 7 4 8 6 4 2 3 4 5 6 7 8 9 0 ); iteration: 1000. encryptionKey _ pbe pbkdf1. pbe clearSensitiveData. encryptionKey inspect Things to note here include: * You can pass a string or a byte array as a password. It doesn't matter. * The salt is some "randomly" chosen string of bytes, it's probably important to note that the salt does not have to be secret. * Though the salt doesn't have to be secret, it can't be guessable, so the example above is "wrong" in that regard. * You can have any iteration count you like. The spec currently recommends at least 1000. * The code was intended to be understandable, not efficient. And it shows. Don't freak out if it takes a little longer than you think it should. There's another way to derive a key which allows you to pick the type of hash function you want to use: | encryptionKey pbe | pbe _ ( PasswordBasedEncryptor new ) password: 'you can have a very long passphrase if you like'; salt: #( 8 3 4 2 5 6 7 4 8 6 4 2 3 4 5 6 7 8 9 0 ); iteration: 1000. encryptionKey _ pbe pbkdf1withDigestor( SHA256 new ). pbe clearSensitiveData. encryptionKey inspect This is interesting because it allows you to pick a message digest code with a larger digest size. This is useful if the first form does not generate enough bits for your requirements. The first form uses a SHA1 function by default which generates 160 bits of output; not especially useful if you're trying to derive a key for an cipher that uses 256 bit keys. ! MessageDigest subclass: #SHA1 instanceVariableNames: 'bitCount byteBuffer byteCount state savedState wordBuffer workBuffer' classVariableNames: 'K' poolDictionaries: '' category: 'Spoon-Crypto'! MessageDigest subclass: #SHA256 instanceVariableNames: 'bitCount byteBuffer byteCount state savedState wordBuffer workBuffer' classVariableNames: 'K' poolDictionaries: '' category: 'Spoon-Crypto'! Object subclass: #SpoonPassword instanceVariableNames: '' classVariableNames: 'MasterKey Passwords' poolDictionaries: '' category: 'Spoon-Security'! !SpoonPassword commentStamp: 'msh 11/7/2005 18:41' prior: 0! The SpoonPassword is one of a long line of simple password holders for Squeakish smalltalks. This one was developed for Spoon. The SpoonPassword class responds to #at: and #at:put: messages so it looks like a dictionary to clients. If you want to "securely" hold a password, you simply add it to the SpoonPassword dictionary like so: SpoonPassword at: 'celeste:account:msh@cryptonomicon.net' put: 'Dingos' To retrieve the password for this account, use the invocation: SpoonPassword at: 'celeste:account:msh@cryptonomicon.net' The next time you save the image, you will be prompted for a master key for the "secure" vault these passwords live in. Now... you might be one of these people that doesn't like being prompted for passwords. That's okay; I understand. I have a list of passwords as long as my arm, and the main purpose of this class is to keep passwords out of images that get sent around on development lists. If you look closely, you'll see that I've added a method to Preferences called #secretVaultPassword. It currently returns nil, but if you set it to return something non-nil, you'll have an image that has the master password for the local copy of your secret vault. This is sorta playing fast and loose with the concept, but hey, I'm all about giving people enough rope to hang themselves. If you're going to set the secretVaultPassword, don't distribute your svault.bin file. -Cheers!! -Matt H.! Object subclass: #SymmetricStreamCipher instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Spoon-Crypto'! SymmetricStreamCipher subclass: #ARC4 instanceVariableNames: 'i j sbox' classVariableNames: '' poolDictionaries: '' category: 'Spoon-Crypto'! !ARC4 commentStamp: '' prior: 0! This class represents an "Alleged RC4" instance. RC4 (tm) is a trademarked symmetric stream cipher from RSA Data Security, Inc. Code for a "RC4 Compatible" cipher was eventually leaked to the internet which is where this implementation comes from. Before using ARC4, you should know that there are a number of terrible attacks against it. Shamir, Mantin, and Flurher documented several weaknesses in the cipher that, in my humble opinion, make it unsafe at any key length. So let's say you want to encrypt something with ARC4. The basic pattern is: initialize with the key, then call the encrypt (or decrypt) functions. ARC4 is a Vernam stream cipher, so we don't have to worry about block size or modes of encryption. Before using any Vernam cipher, however, you should know that it's considered unsafe to encrypt two different messages with the same key. There's more details in Schneier's Applied Crypto or Menezes, et al.'s Handbook of Applied Crypto about this. So, this class takes a key in a byte array, then encrypts plaintext in a byte array to produce a byte array of ciphertext. Here's an example | plaintext ciphertext ncryptor recovered | plaintext _ 'When in the course of human events.' asByteArray. ncryptor _ (ARC4 new). ciphertext _ ncryptor initialize: ('I am a very bad password' asByteArray); encrypt: plaintext. ncryptor clearSensitiveData. ncryptor _ (ARC4 new). recovered _ ncryptor initialize: ('I am a very bad password' asByteArray); encrypt: plaintext. ncryptor clearSensitiveData. At the end of this fragment, plaintext and recovered should both be ByteArray's containing the same data.! !EncryptedStream methodsFor: 'streaming'! atEnd ^ stream atEnd .! ! !EncryptedStream methodsFor: 'streaming'! close stream close.! ! !EncryptedStream methodsFor: 'streaming'! flush stream flush.! ! !EncryptedStream methodsFor: 'streaming' stamp: 'il prior: 34077985!!!!!!!! '! next "This only works for stream ciphers at the moment." | inBuffer outBuffer nextC | "wow. this is patently laughable. Creating a new ByteArray each time you want to decrypt" "a single character in an encrypted stream. Oh well... gives me an opportunity to" "dramatically increase performance later." inBuffer _ ByteArray new: 1. outBuffer _ ByteArray new: 1. inBuffer at: 1 put: ( ( stream next ) asInteger ). ncryptor decrypt: inBuffer into: outBuffer. nextC _ outBuffer at: 1. outBuffer at: 1 put: 0. inBuffer at: 1 put: 0. ^ nextC . ! ! !EncryptedStream methodsFor: 'streaming' stamp: 'msh 11/7/2005 12:56'! nextPut: aChar "This only works for stream ciphers at the moment." | inBuffer outBuffer | "wow. this is patently laughable. Creating a new ByteArray each time you want to decrypt" "a single character in an encrypted stream. Oh well... gives me an opportunity to" "dramatically increase performance later." inBuffer _ ByteArray new: 1. outBuffer _ ByteArray new: 1. inBuffer at: 1 put: ( aChar asInteger ). ncryptor encrypt: inBuffer into: outBuffer. stream nextPut: ( ( outBuffer at: 1 ) asCharacter ). inBuffer at: 1 put: 0. outBuffer at: 1 put: 0. ! ! !EncryptedStream methodsFor: 'private'! ncryptor: anEncryptor ncryptor _ anEncryptor.! ! !EncryptedStream methodsFor: 'private'! stream: aStream stream _ aStream.! ! !EncryptedStream class methodsFor: 'initialization' stamp: 'msh 11/7/2005 12:53'! on: aStream with: anEncryptor ^ (self basicNew) ncryptor: anEncryptor; stream: aStream.! ! !MessageDigest methodsFor: 'output size' stamp: 'msh 6/16/2003 23:16'! outputSize: anInteger "Given in input block of size anInteger, return the size of the output (in bytes)." ^ self outputSize .! ! !MessageDigest methodsFor: 'sensitive data' stamp: 'msh 6/16/2003 23:18'! clearSensitiveData self reinitialize.! ! !MessageDigest methodsFor: 'digesting' stamp: 'msh 6/16/2003 23:20'! digest "return a digest, based on the content of the digesting context." | rv | rv _ ByteArray new: ( self outputSize ). self digest: rv at: 1. ^ rv .! ! !MessageDigest methodsFor: 'digesting' stamp: 'msh 6/16/2003 23:24'! update: aByteArray self update: aByteArray at: 1 count: (aByteArray size).! ! !MessageDigest methodsFor: 'private' stamp: 'msh 6/16/2003 23:22'! leftRotate: anInteger by: bits ^ (anInteger << bits) bitOr: (anInteger >> (32 - bits)) .! ! !MessageDigest methodsFor: 'private' stamp: 'msh 6/17/2003 02:11'! rightRotate: anInteger by: bits ^ (anInteger >> bits) bitOr: (anInteger << (32 - bits)) .! ! !MD2 methodsFor: 'private' stamp: 'msh 6/13/2003 01:14'! initialize "this method is evoked once by the new method. Do not call this method to initialize" "an instance of this class, call reinitialize instead." checksum _ ByteArray new: 16. count _ 1. state _ ByteArray new: 48.! ! !MD2 methodsFor: 'private' stamp: 'msh 6/13/2003 01:20'! transform "Apply the MD2 transform to the current state" | t | t _ checksum at: 16. 1 to: 16 do: [ :i | t _ (checksum at: i) bitXor: (Sbox at: (((state at: (16 +i)) bitXor: t) + 1) ). checksum at: i put: t. ]. t _ 0. 1 to: 18 do: [ :i | 1 to: 48 do: [ :j | t _ (state at: j) bitXor: (Sbox at: (1 + t) ). state at: j put: t. ]. t _ ( t + i - 1 ) bitAnd: 16rFF. ]. count _ 1.! ! !MD2 methodsFor: 'digesting' stamp: 'msh 6/13/2003 01:10'! digest: aByteArray at: anInteger "return a digest, based on the content of the digesting context." self update: (MD2Padding at: count). self update: checksum. 1 to: 16 do: [ :i | aByteArray at: (anInteger + i - 1) put: (state at: i). ].! ! !MD2 methodsFor: 'digesting' stamp: 'msh 6/13/2003 01:06'! reinitialize "This method reinitializes the state of the current MD2 context." 1 to: (checksum size) do: [ :i | checksum at: i put: 0.]. count _ 1. 1 to: (state size) do: [ :i | state at: i put: 0.].! ! !MD2 methodsFor: 'digesting' stamp: 'msh 6/13/2003 01:10'! update: aByteArray at: anIndex count: aCount "update the digesting context with the contents of aByteArray." anIndex to: (anIndex + aCount - 1) do: [ :i | state at: (16 + count) put: (aByteArray at: i). state at: (32 + count) put: ((state at: count) bitXor: (aByteArray at: i)). count _ count + 1. (count > 16) ifTrue: [ self transform. ]. ].! ! !MD2 methodsFor: 'output size' stamp: 'msh 6/13/2003 01:07'! outputSize ^16.! ! !MD4 methodsFor: 'output size' stamp: 'msh 6/13/2003 01:39'! outputSize ^16.! ! !MD4 methodsFor: 'digesting' stamp: 'msh 6/16/2003 18:20'! digest: aByteArray at: anIndex | currentBitCount mask | currentBitCount _ bitCount. "append padding" ( byteCount < 56 ) ifTrue: [ self update: Padding at: 1 count: ( 56 - byteCount ). ] ifFalse: [ self update: Padding at: 1 count: ( 121 - byteCount ). ]. "add bit count" mask _ 16rFF00000000000000. 1 to: 8 do: [ :i | byteBuffer at: ( 65 - i ) put: ( (currentBitCount bitAnd: mask) >> ( (8 - i) * 8 ) ). mask _ mask >> 8. ]. "transform the final buffer" self transform. "write state to output" aByteArray at: (3 + anIndex) put: ( ( ( state at: 1 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (2 + anIndex) put: ( ( ( state at: 1 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (1 + anIndex) put: ( ( ( state at: 1 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (anIndex) put: ( ( state at: 1 ) bitAnd: 16rFF ). aByteArray at: (7 + anIndex) put: ( ( ( state at: 2 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (6 + anIndex) put: ( ( ( state at: 2 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (5 + anIndex) put: ( ( ( state at: 2 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (4 + anIndex) put: ( ( state at: 2 ) bitAnd: 16rFF ). aByteArray at: (11 + anIndex) put: ( ( ( state at: 3 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (10 + anIndex) put: ( ( ( state at: 3 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (9 + anIndex) put: ( ( ( state at: 3 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (8 + anIndex) put: ( ( state at: 3 ) bitAnd: 16rFF ). aByteArray at: (15 + anIndex) put: ( ( ( state at: 4 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (14 + anIndex) put: ( ( ( state at: 4 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (13 + anIndex) put: ( ( ( state at: 4 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (12 + anIndex) put: ( ( state at: 4 ) bitAnd: 16rFF ).! ! !MD4 methodsFor: 'digesting' stamp: 'msh 6/16/2003 18:02'! reinitialize bitCount _ 0. 1 to: (byteBuffer size) do: [ :i | byteBuffer at: i put: 0 ]. byteCount _ 0. 1 to: (savedState size) do: [ :i | savedState at: i put: 0 ]. state at: 1 put: 16r67452301. state at: 2 put: 16rEFCDAB89. state at: 3 put: 16r98BADCFE. state at: 4 put: 16r10325476. 1 to: (wordBuffer size) do: [ :i | wordBuffer at: i put: 0 ].! ! !MD4 methodsFor: 'digesting' stamp: 'msh 6/16/2003 18:17'! update: aByteArray at: anIndex count: aCount "update the digesting context with the contents of aByteArray." anIndex to: (anIndex + aCount - 1) do: [ :i | byteCount _ byteCount + 1. bitCount _ bitCount + 8. ( byteCount > 64 ) ifTrue: [ byteCount _ 1. self transform. ]. byteBuffer at: byteCount put: (aByteArray at: i). ].! ! !MD4 methodsFor: 'private' stamp: 'msh 6/16/2003 18:10'! bufferConvert "Convert the contents of the byte array byteBuffer into the word array wordBuffer. " | j | 1 to: 16 do: [:i | j _ i - 1 * 4 + 1. wordBuffer at: i put: ((((byteBuffer at: j) bitOr: (byteBuffer at: 1 + j) << 8) bitOr: (byteBuffer at: 2 + j) << 16) bitOr: (byteBuffer at: 3 + j) << 24)]! ! !MD4 methodsFor: 'private' stamp: 'msh 6/16/2003 00:42'! ff: a with: b with: c with: d with: x with: s | t | t _ ( ( wordBuffer at: x ) + ( ( state at: a) + ( ( ( state at: b ) bitAnd: ( state at: c ) ) bitOr: ( ( ( state at: b ) bitInvert ) bitAnd: ( state at: d ) ) ) ) ). state at: a put: ( ( self leftRotate: ( t bitAnd: 16rFFFFFFFF ) by: s ) bitAnd: 16rFFFFFFFF ). t _ 0.! ! !MD4 methodsFor: 'private' stamp: 'msh 6/16/2003 00:42'! gg: a with: b with: c with: d with: x with: s | t | t _ ( 16r5A827999 + ( ( wordBuffer at: x ) + ( ( state at: a ) + ( ( ( state at: b ) bitAnd: ( state at: c ) ) bitOr: ( ( ( state at: b ) bitAnd: ( state at: d ) ) bitOr: ( ( state at: c ) bitAnd: ( state at: d ) ) ) ) ) ) ). state at: a put: ( ( self leftRotate: ( t bitAnd: 16rFFFFFFFF ) by: s ) bitAnd: 16rFFFFFFFF ). t _ 0. ! ! !MD4 methodsFor: 'private' stamp: 'msh 6/16/2003 00:44'! hh: a with: b with: c with: d with: x with: s |t| t _ ( 16r6ED9EBA1 + ( ( wordBuffer at: x ) + ( ( state at: a ) + ( ( state at: b ) bitXor: ( ( state at: c ) bitXor: ( state at: d ) ) ) ) ) ). state at: a put: ( ( self leftRotate: ( t bitAnd: 16rFFFFFFFF ) by: s ) bitAnd: 16rFFFFFFFF ). t _ 0.! ! !MD4 methodsFor: 'private' stamp: 'msh 11/7/2005 01:46'! initialize "this method is evoked once by the new method. Do not call this method to initialize" "an instance of this class, call reinitialize instead." bitCount _ 0. byteBuffer _ ByteArray new: 64. byteCount _ 0. savedState _ Array new: 4. state _ Array new: 4. state at: 1 put: 16r67452301. state at: 2 put: 16rEFCDAB89. state at: 3 put: 16r98BADCFE. state at: 4 put: 16r10325476. wordBuffer _ Array new: 16.! ! !MD4 methodsFor: 'private' stamp: 'msh 6/16/2003 18:20'! transform self bufferConvert. 1 to: 4 do: [ :i | savedState at: i put: (state at: i) ]. self ff: 1 with: 2 with: 3 with: 4 with: 1 with: 3. self ff: 4 with: 1 with: 2 with: 3 with: 2 with: 7. self ff: 3 with: 4 with: 1 with: 2 with: 3 with: 11. self ff: 2 with: 3 with: 4 with: 1 with: 4 with: 19. self ff: 1 with: 2 with: 3 with: 4 with: 5 with: 3. self ff: 4 with: 1 with: 2 with: 3 with: 6 with: 7. self ff: 3 with: 4 with: 1 with: 2 with: 7 with: 11. self ff: 2 with: 3 with: 4 with: 1 with: 8 with: 19. self ff: 1 with: 2 with: 3 with: 4 with: 9 with: 3. self ff: 4 with: 1 with: 2 with: 3 with: 10 with: 7. self ff: 3 with: 4 with: 1 with: 2 with: 11 with: 11. self ff: 2 with: 3 with: 4 with: 1 with: 12 with: 19. self ff: 1 with: 2 with: 3 with: 4 with: 13 with: 3. self ff: 4 with: 1 with: 2 with: 3 with: 14 with: 7. self ff: 3 with: 4 with: 1 with: 2 with: 15 with: 11. self ff: 2 with: 3 with: 4 with: 1 with: 16 with: 19. self gg: 1 with: 2 with: 3 with: 4 with: 1 with: 3. self gg: 4 with: 1 with: 2 with: 3 with: 5 with: 5. self gg: 3 with: 4 with: 1 with: 2 with: 9 with: 9. self gg: 2 with: 3 with: 4 with: 1 with: 13 with: 13. self gg: 1 with: 2 with: 3 with: 4 with: 2 with: 3. self gg: 4 with: 1 with: 2 with: 3 with: 6 with: 5. self gg: 3 with: 4 with: 1 with: 2 with: 10 with: 9. self gg: 2 with: 3 with: 4 with: 1 with: 14 with: 13. self gg: 1 with: 2 with: 3 with: 4 with: 3 with: 3. self gg: 4 with: 1 with: 2 with: 3 with: 7 with: 5. self gg: 3 with: 4 with: 1 with: 2 with: 11 with: 9. self gg: 2 with: 3 with: 4 with: 1 with: 15 with: 13. self gg: 1 with: 2 with: 3 with: 4 with: 4 with: 3. self gg: 4 with: 1 with: 2 with: 3 with: 8 with: 5. self gg: 3 with: 4 with: 1 with: 2 with: 12 with: 9. self gg: 2 with: 3 with: 4 with: 1 with: 16 with: 13. self hh: 1 with: 2 with: 3 with: 4 with: 1 with: 3. self hh: 4 with: 1 with: 2 with: 3 with: 9 with: 9. self hh: 3 with: 4 with: 1 with: 2 with: 5 with: 11. self hh: 2 with: 3 with: 4 with: 1 with: 13 with: 15. self hh: 1 with: 2 with: 3 with: 4 with: 3 with: 3. self hh: 4 with: 1 with: 2 with: 3 with: 11 with: 9. self hh: 3 with: 4 with: 1 with: 2 with: 7 with: 11. self hh: 2 with: 3 with: 4 with: 1 with: 15 with: 15. self hh: 1 with: 2 with: 3 with: 4 with: 2 with: 3. self hh: 4 with: 1 with: 2 with: 3 with: 10 with: 9. self hh: 3 with: 4 with: 1 with: 2 with: 6 with: 11. self hh: 2 with: 3 with: 4 with: 1 with: 14 with: 15. self hh: 1 with: 2 with: 3 with: 4 with: 4 with: 3. self hh: 4 with: 1 with: 2 with: 3 with: 12 with: 9. self hh: 3 with: 4 with: 1 with: 2 with: 8 with: 11. self hh: 2 with: 3 with: 4 with: 1 with: 16 with: 15. 1 to: 4 do: [ :i | state at: i put: ( ( ( state at: i ) +( savedState at: i ) ) bitAnd: 16rFFFFFFFF). savedState at: i put: 0. ].! ! !MD5 methodsFor: 'output size' stamp: 'msh 6/16/2003 08:46'! outputSize ^16.! ! !MD5 methodsFor: 'private' stamp: 'msh 6/16/2003 08:45'! bufferConvert "Convert the contents of the byte array byteBuffer into the word array wordBuffer. " | j | 1 to: 16 do: [:i | j _ i - 1 * 4 + 1. wordBuffer at: i put: ((((byteBuffer at: j) bitOr: (byteBuffer at: 1 + j) << 8) bitOr: (byteBuffer at: 2 + j) << 16) bitOr: (byteBuffer at: 3 + j) << 24)]! ! !MD5 methodsFor: 'private' stamp: 'msh 6/16/2003 11:05'! ff: a with: b with: c with: d with: x with: s with: ac | t | t _ ( T at: ac ) + (wordBuffer at: x) + (state at: a) + (((state at: b) bitAnd: (state at: c)) bitOr: ((state at: b) bitInvert bitAnd: (state at: d))). state at: a put: ((self leftRotate: (t bitAnd: 16rFFFFFFFF) by: s) bitAnd: 16rFFFFFFFF). t _ 0. state at: a put: ( ( (state at: a) + (state at: b) ) bitAnd: 16rFFFFFFFF ).! ! !MD5 methodsFor: 'private' stamp: 'msh 6/16/2003 11:05'! gg: a with: b with: c with: d with: x with: s with: ac | t | t _ ( T at: ac ) + (wordBuffer at: x) + (state at: a) + (((state at: b) bitAnd: (state at: d)) bitOr: ((state at: c) bitAnd: (state at: d) bitInvert)). state at: a put: ((self leftRotate: (t bitAnd: 16rFFFFFFFF) by: s) bitAnd: 16rFFFFFFFF). t _ 0. state at: a put: ( ( (state at: a) + (state at: b) ) bitAnd: 16rFFFFFFFF ).! ! !MD5 methodsFor: 'private' stamp: 'msh 6/16/2003 11:05'! hh: a with: b with: c with: d with: x with: s with: ac | t | t _ ( T at: ac ) + (wordBuffer at: x) + (state at: a) + (((state at: b) bitXor: (state at: c)) bitXor: (state at: d)). state at: a put: ((self leftRotate: (t bitAnd: 16rFFFFFFFF) by: s) bitAnd: 16rFFFFFFFF). t _ 0. state at: a put: ( ( (state at: a) + (state at: b) ) bitAnd: 16rFFFFFFFF ).! ! !MD5 methodsFor: 'private' stamp: 'msh 6/16/2003 11:05'! ii: a with: b with: c with: d with: x with: s with: ac | t | t _ ( T at: ac ) + (wordBuffer at: x) + (state at: a) + ((state at: c) bitXor: ((state at: b) bitOr: (state at: d) bitInvert)). state at: a put: ((self leftRotate: (t bitAnd: 16rFFFFFFFF) by: s) bitAnd: 16rFFFFFFFF). t _ 0. state at: a put: ( ( (state at: a) + (state at: b) ) bitAnd: 16rFFFFFFFF ).! ! !MD5 methodsFor: 'private' stamp: 'msh 11/7/2005 01:46'! initialize "this method is evoked once by the new method. Do not call this method to initialize" "an instance of this class, call reinitialize instead." bitCount _ 0. byteBuffer _ ByteArray new: 64. byteCount _ 0. savedState _ Array new: 4. state _ Array new: 4. state at: 1 put: 16r67452301. state at: 2 put: 16rEFCDAB89. state at: 3 put: 16r98BADCFE. state at: 4 put: 16r10325476. wordBuffer _ Array new: 16.! ! !MD5 methodsFor: 'private' stamp: 'msh 6/16/2003 17:15'! transform self bufferConvert. 1 to: 4 do: [ :i | savedState at: i put: ( state at: i ). ]. self ff: 1 with: 2 with: 3 with: 4 with: 1 with: 7 with: 1. self ff: 4 with: 1 with: 2 with: 3 with: 2 with: 12 with: 2. self ff: 3 with: 4 with: 1 with: 2 with: 3 with: 17 with: 3. self ff: 2 with: 3 with: 4 with: 1 with: 4 with: 22 with: 4. self ff: 1 with: 2 with: 3 with: 4 with: 5 with: 7 with: 5. self ff: 4 with: 1 with: 2 with: 3 with: 6 with: 12 with: 6. self ff: 3 with: 4 with: 1 with: 2 with: 7 with: 17 with: 7. self ff: 2 with: 3 with: 4 with: 1 with: 8 with: 22 with: 8. self ff: 1 with: 2 with: 3 with: 4 with: 9 with: 7 with: 9. self ff: 4 with: 1 with: 2 with: 3 with: 10 with: 12 with: 10. self ff: 3 with: 4 with: 1 with: 2 with: 11 with: 17 with: 11. self ff: 2 with: 3 with: 4 with: 1 with: 12 with: 22 with: 12. self ff: 1 with: 2 with: 3 with: 4 with: 13 with: 7 with: 13. self ff: 4 with: 1 with: 2 with: 3 with: 14 with: 12 with: 14. self ff: 3 with: 4 with: 1 with: 2 with: 15 with: 17 with: 15. self ff: 2 with: 3 with: 4 with: 1 with: 16 with: 22 with: 16. self gg: 1 with: 2 with: 3 with: 4 with: 2 with: 5 with: 17. self gg: 4 with: 1 with: 2 with: 3 with: 7 with: 9 with: 18. self gg: 3 with: 4 with: 1 with: 2 with: 12 with: 14 with: 19. self gg: 2 with: 3 with: 4 with: 1 with: 1 with: 20 with: 20. self gg: 1 with: 2 with: 3 with: 4 with: 6 with: 5 with: 21. self gg: 4 with: 1 with: 2 with: 3 with: 11 with: 9 with: 22. self gg: 3 with: 4 with: 1 with: 2 with: 16 with: 14 with: 23. self gg: 2 with: 3 with: 4 with: 1 with: 5 with: 20 with: 24. self gg: 1 with: 2 with: 3 with: 4 with: 10 with: 5 with: 25. self gg: 4 with: 1 with: 2 with: 3 with: 15 with: 9 with: 26. self gg: 3 with: 4 with: 1 with: 2 with: 4 with: 14 with: 27. self gg: 2 with: 3 with: 4 with: 1 with: 9 with: 20 with: 28. self gg: 1 with: 2 with: 3 with: 4 with: 14 with: 5 with: 29. self gg: 4 with: 1 with: 2 with: 3 with: 3 with: 9 with: 30. self gg: 3 with: 4 with: 1 with: 2 with: 8 with: 14 with: 31. self gg: 2 with: 3 with: 4 with: 1 with: 13 with: 20 with: 32. self hh: 1 with: 2 with: 3 with: 4 with: 6 with: 4 with: 33. self hh: 4 with: 1 with: 2 with: 3 with: 9 with: 11 with: 34. self hh: 3 with: 4 with: 1 with: 2 with: 12 with: 16 with: 35. self hh: 2 with: 3 with: 4 with: 1 with: 15 with: 23 with: 36. self hh: 1 with: 2 with: 3 with: 4 with: 2 with: 4 with: 37. self hh: 4 with: 1 with: 2 with: 3 with: 5 with: 11 with: 38. self hh: 3 with: 4 with: 1 with: 2 with: 8 with: 16 with: 39. self hh: 2 with: 3 with: 4 with: 1 with: 11 with: 23 with: 40. self hh: 1 with: 2 with: 3 with: 4 with: 14 with: 4 with: 41. self hh: 4 with: 1 with: 2 with: 3 with: 1 with: 11 with: 42. self hh: 3 with: 4 with: 1 with: 2 with: 4 with: 16 with: 43. self hh: 2 with: 3 with: 4 with: 1 with: 7 with: 23 with: 44. self hh: 1 with: 2 with: 3 with: 4 with: 10 with: 4 with: 45. self hh: 4 with: 1 with: 2 with: 3 with: 13 with: 11 with: 46. self hh: 3 with: 4 with: 1 with: 2 with: 16 with: 16 with: 47. self hh: 2 with: 3 with: 4 with: 1 with: 3 with: 23 with: 48. self ii: 1 with: 2 with: 3 with: 4 with: 1 with: 6 with: 49. self ii: 4 with: 1 with: 2 with: 3 with: 8 with: 10 with: 50. self ii: 3 with: 4 with: 1 with: 2 with: 15 with: 15 with: 51. self ii: 2 with: 3 with: 4 with: 1 with: 6 with: 21 with: 52. self ii: 1 with: 2 with: 3 with: 4 with: 13 with: 6 with: 53. self ii: 4 with: 1 with: 2 with: 3 with: 4 with: 10 with: 54. self ii: 3 with: 4 with: 1 with: 2 with: 11 with: 15 with: 55. self ii: 2 with: 3 with: 4 with: 1 with: 2 with: 21 with: 56. self ii: 1 with: 2 with: 3 with: 4 with: 9 with: 6 with: 57. self ii: 4 with: 1 with: 2 with: 3 with: 16 with: 10 with: 58. self ii: 3 with: 4 with: 1 with: 2 with: 7 with: 15 with: 59. self ii: 2 with: 3 with: 4 with: 1 with: 14 with: 21 with: 60. self ii: 1 with: 2 with: 3 with: 4 with: 5 with: 6 with: 61. self ii: 4 with: 1 with: 2 with: 3 with: 12 with: 10 with: 62. self ii: 3 with: 4 with: 1 with: 2 with: 3 with: 15 with: 63. self ii: 2 with: 3 with: 4 with: 1 with: 10 with: 21 with: 64. 1 to: 4 do: [ :i | state at: i put: (((state at: i) + (savedState at: i)) bitAnd: 16rFFFFFFFF). savedState at: i put: 0. ].! ! !MD5 methodsFor: 'digesting' stamp: 'msh 6/16/2003 13:54'! digest: aByteArray at: anIndex | currentBitCount mask | currentBitCount _ bitCount. "append padding" ( byteCount < 56 ) ifTrue: [ self update: Padding at: 1 count: ( 56 - byteCount ). ] ifFalse: [ self update: Padding at: 1 count: ( 121 - byteCount ). ]. "add bit count" mask _ 16rFF00000000000000. 1 to: 8 do: [ :i | byteBuffer at: ( 65 - i ) put: ( (currentBitCount bitAnd: mask) >> ( (8 - i) * 8 ) ). mask _ mask >> 8. ]. "transform the final buffer" self transform. "write state to output" aByteArray at: (3 + anIndex) put: ( ( ( state at: 1 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (2 + anIndex) put: ( ( ( state at: 1 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (1 + anIndex) put: ( ( ( state at: 1 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (anIndex) put: ( ( state at: 1 ) bitAnd: 16rFF ). aByteArray at: (7 + anIndex) put: ( ( ( state at: 2 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (6 + anIndex) put: ( ( ( state at: 2 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (5 + anIndex) put: ( ( ( state at: 2 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (4 + anIndex) put: ( ( state at: 2 ) bitAnd: 16rFF ). aByteArray at: (11 + anIndex) put: ( ( ( state at: 3 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (10 + anIndex) put: ( ( ( state at: 3 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (9 + anIndex) put: ( ( ( state at: 3 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (8 + anIndex) put: ( ( state at: 3 ) bitAnd: 16rFF ). aByteArray at: (15 + anIndex) put: ( ( ( state at: 4 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (14 + anIndex) put: ( ( ( state at: 4 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (13 + anIndex) put: ( ( ( state at: 4 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (12 + anIndex) put: ( ( state at: 4 ) bitAnd: 16rFF ).! ! !MD5 methodsFor: 'digesting' stamp: 'msh 6/16/2003 09:24'! reinitialize bitCount _ 0. 1 to: (byteBuffer size) do: [ :i | byteBuffer at: i put: 0 ]. byteCount _ 0. 1 to: (savedState size) do: [ :i | savedState at: i put: 0 ]. state at: 1 put: 16r67452301. state at: 2 put: 16rEFCDAB89. state at: 3 put: 16r98BADCFE. state at: 4 put: 16r10325476. 1 to: (wordBuffer size) do: [ :i | wordBuffer at: i put: 0 ].! ! !MD5 methodsFor: 'digesting' stamp: 'msh 6/16/2003 17:15'! update: aByteArray at: anIndex count: aCount anIndex to: (anIndex + aCount - 1) do: [ :i | byteCount _ byteCount + 1. bitCount _ bitCount + 8. ( byteCount > 64 ) ifTrue: [ byteCount _ 1. self transform. ]. byteBuffer at: byteCount put: ( aByteArray at: i ). ].! ! !MessageDigest class methodsFor: 'class initialization' stamp: 'msh 6/16/2003 23:46'! initialize Padding _ #(128 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ).! ! !MD2 class methodsFor: 'class initialization' stamp: 'msh 6/16/2003 23:40'! initialize "Initialize the Sbox and MD2Padding class variables." Sbox _ #( 16r29 16r2E 16r43 16rC9 16rA2 16rD8 16r7C 16r01 16r3D 16r36 16r54 16rA1 16rEC 16rF0 16r06 16r13 16r62 16rA7 16r05 16rF3 16rC0 16rC7 16r73 16r8C 16r98 16r93 16r2B 16rD9 16rBC 16r4C 16r82 16rCA 16r1E 16r9B 16r57 16r3C 16rFD 16rD4 16rE0 16r16 16r67 16r42 16r6F 16r18 16r8A 16r17 16rE5 16r12 16rBE 16r4E 16rC4 16rD6 16rDA 16r9E 16rDE 16r49 16rA0 16rFB 16rF5 16r8E 16rBB 16r2F 16rEE 16r7A 16rA9 16r68 16r79 16r91 16r15 16rB2 16r07 16r3F 16r94 16rC2 16r10 16r89 16r0B 16r22 16r5F 16r21 16r80 16r7F 16r5D 16r9A 16r5A 16r90 16r32 16r27 16r35 16r3E 16rCC 16rE7 16rBF 16rF7 16r97 16r03 16rFF 16r19 16r30 16rB3 16r48 16rA5 16rB5 16rD1 16rD7 16r5E 16r92 16r2A 16rAC 16r56 16rAA 16rC6 16r4F 16rB8 16r38 16rD2 16r96 16rA4 16r7D 16rB6 16r76 16rFC 16r6B 16rE2 16r9C 16r74 16r04 16rF1 16r45 16r9D 16r70 16r59 16r64 16r71 16r87 16r20 16r86 16r5B 16rCF 16r65 16rE6 16r2D 16rA8 16r02 16r1B 16r60 16r25 16rAD 16rAE 16rB0 16rB9 16rF6 16r1C 16r46 16r61 16r69 16r34 16r40 16r7E 16r0F 16r55 16r47 16rA3 16r23 16rDD 16r51 16rAF 16r3A 16rC3 16r5C 16rF9 16rCE 16rBA 16rC5 16rEA 16r26 16r2C 16r53 16r0D 16r6E 16r85 16r28 16r84 16r09 16rD3 16rDF 16rCD 16rF4 16r41 16r81 16r4D 16r52 16r6A 16rDC 16r37 16rC8 16r6C 16rC1 16rAB 16rFA 16r24 16rE1 16r7B 16r08 16r0C 16rBD 16rB1 16r4A 16r78 16r88 16r95 16r8B 16rE3 16r63 16rE8 16r6D 16rE9 16rCB 16rD5 16rFE 16r3B 16r00 16r1D 16r39 16rF2 16rEF 16rB7 16r0E 16r66 16r58 16rD0 16rE4 16rA6 16r77 16r72 16rF8 16rEB 16r75 16r4B 16r0A 16r31 16r44 16r50 16rB4 16r8F 16rED 16r1F 16r1A 16rDB 16r99 16r8D 16r33 16r9F 16r11 16r83 16r14 ). MD2Padding _ #( #( 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 ) #( 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 ) #( 14 14 14 14 14 14 14 14 14 14 14 14 14 14 ) #( 13 13 13 13 13 13 13 13 13 13 13 13 13 ) #( 12 12 12 12 12 12 12 12 12 12 12 12 ) #( 11 11 11 11 11 11 11 11 11 11 11 ) #( 10 10 10 10 10 10 10 10 10 10 ) #( 9 9 9 9 9 9 9 9 9 ) #( 8 8 8 8 8 8 8 8 ) #( 7 7 7 7 7 7 7 ) #( 6 6 6 6 6 6 ) #( 5 5 5 5 5 ) #( 4 4 4 4 ) #( 3 3 3 ) #( 2 2 ) #( 1 ) ). ! ! !MD2 class methodsFor: 'instance creation' stamp: 'msh 6/13/2003 01:02'! new ^super new initialize.! ! !MD4 class methodsFor: 'instance creation' stamp: 'msh 6/13/2003 01:23'! new ^super new initialize.! ! !MD5 class methodsFor: 'instance creation' stamp: 'msh 6/16/2003 08:37'! new ^super new initialize.! ! !MD5 class methodsFor: 'class initialization' stamp: 'msh 6/16/2003 22:28'! initialize T _ #( 16rD76AA478 16rE8C7B756 16r242070DB 16rC1BDCEEE 16rF57C0FAF 16r4787C62A 16rA8304613 16rFD469501 16r698098D8 16r8B44F7AF 16rFFFF5BB1 16r895CD7BE 16r6B901122 16rFD987193 16rA679438E 16r49B40821 16rF61E2562 16rC040B340 16r265E5A51 16rE9B6C7AA 16rD62F105D 16r2441453 16rD8A1E681 16rE7D3FBC8 16r21E1CDE6 16rC33707D6 16rF4D50D87 16r455A14ED 16rA9E3E905 16rFCEFA3F8 16r676F02D9 16r8D2A4C8A 16rFFFA3942 16r8771F681 16r6D9D6122 16rFDE5380C 16rA4BEEA44 16r4BDECFA9 16rF6BB4B60 16rBEBFBC70 16r289B7EC6 16rEAA127FA 16rD4EF3085 16r4881D05 16rD9D4D039 16rE6DB99E5 16r1FA27CF8 16rC4AC5665 16rF4292244 16r432AFF97 16rAB9423A7 16rFC93A039 16r655B59C3 16r8F0CCC92 16rFFEFF47D 16r85845DD1 16r6FA87E4F 16rFE2CE6E0 16rA3014314 16r4E0811A1 16rF7537E82 16rBD3AF235 16r2AD7D2BB 16rEB86D391 ). ! ! !PasswordBasedEncryptor methodsFor: 'key derivation' stamp: 'msh 5/4/2005 18:43'! pbkdf1 "returns a byte array containing derived key." ^ self pbkdf1withDigestor: ( SHA1 new ) .! ! !PasswordBasedEncryptor methodsFor: 'key derivation' stamp: 'msh 5/4/2005 18:05'! pbkdf1withDigestor: aDigestor "returns a byte array containing derived key using the given digest object." | derivedKey | derivedKey _ ByteArray new: (aDigestor outputSize). self pbkdf1withDigestor: aDigestor on: derivedKey atOffset: 1 withLength: ( derivedKey size ). ^ derivedKey . ! ! !PasswordBasedEncryptor methodsFor: 'key derivation' stamp: 'msh 5/4/2005 18:42'! pbkdf1withDigestor: aDigestor on: outputArray atOffset: anIndex withLength: length "returns a byte array containing derived key using the given digest object." | initial passwordArray previous current | initial _ ByteArray new: (password size + salt size). passwordArray _ password asByteArray. 1 to: ( passwordArray size ) do: [ :index | initial at: index put: ( passwordArray at: index ). passwordArray at: index put: 0. ]. 1 to: ( salt size ) do: [ :index | initial at: ( index + ( passwordArray size ) ) put: ( salt at: index ). ]. aDigestor initialize; update: initial. current _ aDigestor digest. 1 to: ( initial size ) do: [ :index | initial at: index put: 0. ]. previous _ ByteArray new: ( current size ). 2 to: iteration do: [ :count | 1 to: ( current size ) do: [ :index | previous at: index put: (current at: index). ]. aDigestor initialize; update: previous; digest: current at: 1. ]. 1 to: ( current size ) do: [ :index | ( index <= length ) ifTrue: [ outputArray at: ( index + anIndex - 1) put: (current at: index). ]. previous at: index put: 0. current at: index put: 0. ]. ! ! !PasswordBasedEncryptor methodsFor: 'accessing' stamp: 'msh 5/4/2005 17:55'! iteration: anInteger iteration _ anInteger.! ! !PasswordBasedEncryptor methodsFor: 'accessing' stamp: 'msh 5/4/2005 18:55'! password: aStringOrArray password _ aStringOrArray asByteArray.! ! !PasswordBasedEncryptor methodsFor: 'accessing' stamp: 'msh 5/4/2005 17:55'! salt: anArray salt _ anArray.! ! !PasswordBasedEncryptor methodsFor: 'sensitive data' stamp: 'msh 5/4/2005 17:54'! clearSensitiveData ( password respondsTo: #clearSensitiveData ) ifTrue: [ password clearSensitiveData. ] ifFalse: [ 1 to: ( password size ) do: [ :index | password at: index put: 0. ]. ]. ! ! !Preferences class methodsFor: 'misc' stamp: 'msh 11/7/2005 18:18'! secretVaultFileName ^ 'svault.bin' .! ! !Preferences class methodsFor: 'misc' stamp: 'msh 11/7/2005 18:18'! secretVaultPassword ^ nil .! ! !SHA1 methodsFor: 'private' stamp: 'msh 6/17/2003 01:18'! bufferConvert "Convert the contents of the byte array byteBuffer into the word array wordBuffer. " | j | 1 to: 16 do: [:i | j _ i - 1 * 4 + 1. wordBuffer at: i put: ((((byteBuffer at: (3 +j) ) bitOr: (byteBuffer at: 2 + j) << 8) bitOr: (byteBuffer at: 1 + j) << 16) bitOr: (byteBuffer at: j) << 24)]! ! !SHA1 methodsFor: 'private' stamp: 'msh 6/17/2003 00:52'! ch ^ (((state at: 2) bitAnd: (state at: 3)) bitXor: (((state at: 2) bitInvert ) bitAnd: (state at: 4))) .! ! !SHA1 methodsFor: 'private' stamp: 'msh 11/7/2005 01:47'! initialize bitCount _ 0. byteBuffer _ ByteArray new: 64. byteCount _ 0. savedState _ Array new: 5. state _ Array new: 5. state at: 1 put: 16r67452301. state at: 2 put: 16rEFCDAB89. state at: 3 put: 16r98BADCFE. state at: 4 put: 16r10325476. state at: 5 put: 16rC3D2E1F0. wordBuffer _ Array new: 16. workBuffer _ Array new: 80.! ! !SHA1 methodsFor: 'private' stamp: 'msh 6/17/2003 00:55'! maj ^ ( ( ( ( state at: 2 ) bitAnd: ( state at: 3 ) ) bitXor: ( ( state at: 2 ) bitAnd: ( state at: 4 ) ) ) bitXor: ( ( state at: 3 ) bitAnd: ( state at: 4 ) ) ).! ! !SHA1 methodsFor: 'private' stamp: 'msh 6/17/2003 00:53'! parity ^ ( ( ( state at: 2 ) bitXor: ( state at: 3 ) ) bitXor: ( state at: 4 ) ).! ! !SHA1 methodsFor: 'private' stamp: 'msh 6/17/2003 01:31'! transform | t | self bufferConvert. 1 to: 16 do: [ :i | workBuffer at: i put: ( wordBuffer at: i ). ]. 17 to: 80 do: [ :i | workBuffer at: i put: ( ( self leftRotate: ( ( ( ( ( workBuffer at: ( i - 3 ) ) bitXor: ( workBuffer at: ( i - 8 ) ) ) bitXor: ( workBuffer at: ( i - 14) ) ) bitXor: ( workBuffer at: ( i - 16) ) ) ) by: 1 ) bitAnd: 16rFFFFFFFF ). ]. 1 to: 5 do: [ :i | savedState at: i put: ( state at: i ). ]. 1 to: 80 do: [ :i | t _ ( (self leftRotate: (state at: 1) by: 5 ) + (state at: 5) + (K at: i) + (workBuffer at: i) ) bitAnd: 16rFFFFFFFF. ( i between: 1 and: 20 ) ifTrue: [ t _ ( t + ( self ch ) ) bitAnd: 16rFFFFFFFF. ]. ( i between: 21 and: 40 ) ifTrue: [ t _ ( t + ( self parity ) ) bitAnd: 16rFFFFFFFF. ]. ( i between: 41 and: 60 ) ifTrue: [ t _ ( t + ( self maj ) ) bitAnd: 16rFFFFFFFF. ]. ( i between: 61 and: 80 ) ifTrue: [ t _ ( t + ( self parity ) ) bitAnd: 16rFFFFFFFF. ]. state at: 5 put: ( state at: 4 ). state at: 4 put: ( state at: 3 ). state at: 3 put: ( ( self leftRotate: (state at: 2) by: 30 ) bitAnd: 16rFFFFFFFF ). state at: 2 put: ( state at: 1 ). state at: 1 put: t. ]. 1 to: 5 do: [ :i | state at: i put: ( ( ( state at: i ) + ( savedState at: i ) ) bitAnd: 16rFFFFFFFF ). ].! ! !SHA1 methodsFor: 'output size' stamp: 'msh 6/17/2003 00:09'! outputSize ^20.! ! !SHA1 methodsFor: 'digesting' stamp: 'msh 6/17/2003 01:31'! digest: aByteArray at: anIndex | currentBitCount mask | currentBitCount _ bitCount. "append padding" ( byteCount < 56 ) ifTrue: [ self update: Padding at: 1 count: ( 56 - byteCount ). ] ifFalse: [ self update: Padding at: 1 count: ( 121 - byteCount ). ]. "add bit count" mask _ 16rFF00000000000000. 1 to: 8 do: [ :i | byteBuffer at: ( 56 + i ) put: ( (currentBitCount bitAnd: mask) >> ( (8 - i) * 8 ) ). mask _ mask >> 8. ]. "transform the final buffer" self transform. "write state to output" aByteArray at: (anIndex) put: ( ( ( state at: 1 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (1 + anIndex) put: ( ( ( state at: 1 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (2 + anIndex) put: ( ( ( state at: 1 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (3 + anIndex) put: ( ( state at: 1 ) bitAnd: 16rFF ). aByteArray at: (4 + anIndex) put: ( ( ( state at: 2 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (5 + anIndex) put: ( ( ( state at: 2 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (6 + anIndex) put: ( ( ( state at: 2 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (7 + anIndex) put: ( ( state at: 2 ) bitAnd: 16rFF ). aByteArray at: (8 + anIndex) put: ( ( ( state at: 3 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (9 + anIndex) put: ( ( ( state at: 3 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (10 + anIndex) put: ( ( ( state at: 3 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (11 + anIndex) put: ( ( state at: 3 ) bitAnd: 16rFF ). aByteArray at: (12 + anIndex) put: ( ( ( state at: 4 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (13 + anIndex) put: ( ( ( state at: 4 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (14 + anIndex) put: ( ( ( state at: 4 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (15 + anIndex) put: ( ( state at: 4 ) bitAnd: 16rFF ). aByteArray at: (16 + anIndex) put: ( ( ( state at: 5 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (17 + anIndex) put: ( ( ( state at: 5 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (18 + anIndex) put: ( ( ( state at: 5 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (19 + anIndex) put: ( ( state at: 5 ) bitAnd: 16rFF ).! ! !SHA1 methodsFor: 'digesting' stamp: 'msh 6/17/2003 00:10'! reinitialize bitCount _ 0. 1 to: (byteBuffer size) do: [ :i | byteBuffer at: i put: 0 ]. byteCount _ 0. 1 to: (savedState size) do: [ :i | savedState at: i put: 0 ]. state at: 1 put: 16r67452301. state at: 2 put: 16rEFCDAB89. state at: 3 put: 16r98BADCFE. state at: 4 put: 16r10325476. state at: 5 put: 16rC3D2E1F0. 1 to: (wordBuffer size) do: [ :i | wordBuffer at: i put: 0 ].! ! !SHA1 methodsFor: 'digesting' stamp: 'msh 6/17/2003 00:10'! update: aByteArray at: anIndex count: aCount anIndex to: (anIndex + aCount - 1) do: [ :i | byteCount _ byteCount + 1. bitCount _ bitCount + 8. ( byteCount > 64 ) ifTrue: [ byteCount _ 1. self transform. ]. byteBuffer at: byteCount put: ( aByteArray at: i ). ].! ! !SHA1 class methodsFor: 'instance creation' stamp: 'msh 6/17/2003 00:02'! new ^super new initialize.! ! !SHA1 class methodsFor: 'class initialization' stamp: 'msh 6/17/2003 00:34'! initialize K _ #( 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r5A827999 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r6ED9EBA1 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16r8F1BBCDC 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 16rCA62C1D6 ).! ! !SHA256 methodsFor: 'output size' stamp: 'msh 6/17/2003 02:29'! outputSize ^32.! ! !SHA256 methodsFor: 'digesting' stamp: 'msh 6/17/2003 01:57'! digest: aByteArray at: anIndex | currentBitCount mask | currentBitCount _ bitCount. "append padding" ( byteCount < 56 ) ifTrue: [ self update: Padding at: 1 count: ( 56 - byteCount ). ] ifFalse: [ self update: Padding at: 1 count: ( 121 - byteCount ). ]. "add bit count" mask _ 16rFF00000000000000. 1 to: 8 do: [ :i | byteBuffer at: ( 56 + i ) put: ( (currentBitCount bitAnd: mask) >> ( (8 - i) * 8 ) ). mask _ mask >> 8. ]. "transform the final buffer" self transform. "write state to output" aByteArray at: (anIndex) put: ( ( ( state at: 1 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (1 + anIndex) put: ( ( ( state at: 1 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (2 + anIndex) put: ( ( ( state at: 1 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (3 + anIndex) put: ( ( state at: 1 ) bitAnd: 16rFF ). aByteArray at: (4 + anIndex) put: ( ( ( state at: 2 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (5 + anIndex) put: ( ( ( state at: 2 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (6 + anIndex) put: ( ( ( state at: 2 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (7 + anIndex) put: ( ( state at: 2 ) bitAnd: 16rFF ). aByteArray at: (8 + anIndex) put: ( ( ( state at: 3 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (9 + anIndex) put: ( ( ( state at: 3 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (10 + anIndex) put: ( ( ( state at: 3 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (11 + anIndex) put: ( ( state at: 3 ) bitAnd: 16rFF ). aByteArray at: (12 + anIndex) put: ( ( ( state at: 4 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (13 + anIndex) put: ( ( ( state at: 4 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (14 + anIndex) put: ( ( ( state at: 4 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (15 + anIndex) put: ( ( state at: 4 ) bitAnd: 16rFF ). aByteArray at: (16 + anIndex) put: ( ( ( state at: 5 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (17 + anIndex) put: ( ( ( state at: 5 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (18 + anIndex) put: ( ( ( state at: 5 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (19 + anIndex) put: ( ( state at: 5 ) bitAnd: 16rFF ). aByteArray at: (20 + anIndex) put: ( ( ( state at: 6 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (21 + anIndex) put: ( ( ( state at: 6 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (22 + anIndex) put: ( ( ( state at: 6 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (23 + anIndex) put: ( ( state at: 6 ) bitAnd: 16rFF ). aByteArray at: (24 + anIndex) put: ( ( ( state at: 7 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (25 + anIndex) put: ( ( ( state at: 7 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (26 + anIndex) put: ( ( ( state at: 7 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (27 + anIndex) put: ( ( state at: 7 ) bitAnd: 16rFF ). aByteArray at: (28 + anIndex) put: ( ( ( state at: 8 ) bitAnd: 16rFF000000 ) >> 24 ). aByteArray at: (29 + anIndex) put: ( ( ( state at: 8 ) bitAnd: 16rFF0000 ) >> 16 ). aByteArray at: (30 + anIndex) put: ( ( ( state at: 8 ) bitAnd: 16rFF00 ) >> 8 ). aByteArray at: (31 + anIndex) put: ( ( state at: 8 ) bitAnd: 16rFF ).! ! !SHA256 methodsFor: 'digesting' stamp: 'msh 6/17/2003 02:27'! reinitialize bitCount _ 0. 1 to: (byteBuffer size) do: [ :i | byteBuffer at: i put: 0 ]. byteCount _ 0. 1 to: (savedState size) do: [ :i | savedState at: i put: 0 ]. state at: 1 put: 16r6A09E667. state at: 2 put: 16rBB67AE85. state at: 3 put: 16r3C6EF372. state at: 4 put: 16rA54FF53A. state at: 5 put: 16r510E527F. state at: 6 put: 16r9B05688C. state at: 7 put: 16r1F83D9AB. state at: 8 put: 16r5BE0CD19. 1 to: (wordBuffer size) do: [ :i | wordBuffer at: i put: 0 ].! ! !SHA256 methodsFor: 'digesting' stamp: 'msh 6/17/2003 02:01'! update: aByteArray at: anIndex count: aCount anIndex to: (anIndex + aCount - 1) do: [ :i | byteCount _ byteCount + 1. bitCount _ bitCount + 8. ( byteCount > 64 ) ifTrue: [ byteCount _ 1. self transform. ]. byteBuffer at: byteCount put: ( aByteArray at: i ). ].! ! !SHA256 methodsFor: 'private' stamp: 'msh 6/17/2003 02:02'! bufferConvert "Convert the contents of the byte array byteBuffer into the word array wordBuffer. " | j | 1 to: 16 do: [:i | j _ i - 1 * 4 + 1. wordBuffer at: i put: ((((byteBuffer at: (3 +j) ) bitOr: (byteBuffer at: 2 + j) << 8) bitOr: (byteBuffer at: 1 + j) << 16) bitOr: (byteBuffer at: j) << 24)]! ! !SHA256 methodsFor: 'private' stamp: 'msh 6/17/2003 02:08'! ch ^ (((state at: 5) bitAnd: (state at: 6)) bitXor: (((state at: 5) bitInvert ) bitAnd: (state at: 7))) .! ! !SHA256 methodsFor: 'private' stamp: 'msh 11/7/2005 01:47'! initialize bitCount _ 0. byteBuffer _ ByteArray new: 64. byteCount _ 0. savedState _ Array new: 8. state _ Array new: 8. state at: 1 put: 16r6A09E667. state at: 2 put: 16rBB67AE85. state at: 3 put: 16r3C6EF372. state at: 4 put: 16rA54FF53A. state at: 5 put: 16r510E527F. state at: 6 put: 16r9B05688C. state at: 7 put: 16r1F83D9AB. state at: 8 put: 16r5BE0CD19. wordBuffer _ Array new: 16. workBuffer _ Array new: 64.! ! !SHA256 methodsFor: 'private' stamp: 'msh 6/17/2003 02:09'! maj ^ ( ( ( ( state at: 1 ) bitAnd: ( state at: 2 ) ) bitXor: ( ( state at: 1 ) bitAnd: ( state at: 3 ) ) ) bitXor: ( ( state at: 2 ) bitAnd: ( state at: 3 ) ) ).! ! !SHA256 methodsFor: 'private' stamp: 'msh 6/17/2003 02:14'! s0: anInteger ^ ((((self rightRotate: anInteger by: 7) bitXor: (self rightRotate: anInteger by: 18)) bitXor: (anInteger >> 3)) bitAnd: 16rFFFFFFFF).! ! !SHA256 methodsFor: 'private' stamp: 'msh 6/17/2003 02:14'! s1: anInteger ^ ((((self rightRotate: anInteger by: 17) bitXor: (self rightRotate: anInteger by: 19)) bitXor: (anInteger >> 10)) bitAnd: 16rFFFFFFFF).! ! !SHA256 methodsFor: 'private' stamp: 'msh 6/17/2003 02:13'! sum0: anInteger ^ ((((self rightRotate: anInteger by: 2) bitXor: (self rightRotate: anInteger by: 13)) bitXor: (self rightRotate: anInteger by: 22)) bitAnd: 16rFFFFFFFF).! ! !SHA256 methodsFor: 'private' stamp: 'msh 6/17/2003 02:13'! sum1: anInteger ^ ((((self rightRotate: anInteger by: 6) bitXor: (self rightRotate: anInteger by: 11)) bitXor: (self rightRotate: anInteger by: 25)) bitAnd: 16rFFFFFFFF).! ! !SHA256 methodsFor: 'private' stamp: 'msh 6/17/2003 02:25'! transform | t1 t2 | self bufferConvert. 1 to: 16 do: [ :i | workBuffer at: i put: ( wordBuffer at: i ). ]. 17 to: 64 do: [ :i | workBuffer at: i put: ( ((self s1:(workBuffer at: (i-2))) + (workBuffer at: (i-7)) + (self s0:(workBuffer at: (i-15))) + (workBuffer at: (i-16))) bitAnd: 16rFFFFFFFF ). ]. 1 to: 8 do: [ :i | savedState at: i put: ( state at: i ). ]. 1 to: 64 do: [ :i | t1 _ ((state at: 8) + (self sum1:(state at: 5)) + (self ch) + (K at: i) + (workBuffer at: i)) bitAnd: 16rFFFFFFFF. t2 _ ((self sum0: (state at: 1)) + (self maj)) bitAnd: 16rFFFFFFFF. state at: 8 put: (state at: 7). state at: 7 put: (state at: 6). state at: 6 put: (state at: 5). state at: 5 put: (((state at: 4) + t1) bitAnd: 16rFFFFFFFF). state at: 4 put: (state at: 3). state at: 3 put: (state at: 2). state at: 2 put: (state at: 1). state at: 1 put: ((t1 + t2) bitAnd: 16rFFFFFFFF). ]. 1 to: 8 do: [ :i | state at: i put: ( ( ( state at: i ) + ( savedState at: i ) ) bitAnd: 16rFFFFFFFF ). ].! ! !SHA256 class methodsFor: 'instance creation' stamp: 'msh 6/17/2003 01:53'! new ^super new initialize.! ! !SHA256 class methodsFor: 'class initialization' stamp: 'msh 6/17/2003 01:55'! initialize K _ #( 16r428A2F98 16r71374491 16rB5C0FBCF 16rE9B5DBA5 16r3956C25B 16r59F111F1 16r923F82A4 16rAB1C5ED5 16rD807AA98 16r12835B01 16r243185BE 16r550C7DC3 16r72BE5D74 16r80DEB1FE 16r9BDC06A7 16rC19BF174 16rE49B69C1 16rEFBE4786 16r0FC19DC6 16r240CA1CC 16r2DE92C6F 16r4A7484AA 16r5CB0A9DC 16r76F988DA 16r983E5152 16rA831C66D 16rB00327C8 16rBF597FC7 16rC6E00BF3 16rD5A79147 16r06CA6351 16r14292967 16r27B70A85 16r2E1B2138 16r4D2C6DFC 16r53380D13 16r650A7354 16r766A0ABB 16r81C2C92E 16r92722C85 16rA2BFE8A1 16rA81A664B 16rC24B8B70 16rC76C51A3 16rD192E819 16rD6990624 16rF40E3585 16r106AA070 16r19A4C116 16r1E376C08 16r2748774C 16r34B0BCB5 16r391C0CB3 16r4ED8AA4A 16r5B9CCA4F 16r682E6FF3 16r748F82EE 16r78A5636F 16r84C87814 16r8CC70208 16r90BEFFFA 16rA4506CEB 16rBEF9A3F7 16rC67178F2 ).! ! !SpoonPassword class methodsFor: 'accessing'! at: aKey "return the shared secret referenced by aKey. In other words, we created a password for" "the SpoonPassword class to manage. So instead of holding a password, the application class holds" "a reference to the password. That reference is a simple descriptive string like:" "celeste:account:msh@cryptonomicon.net" "This is an example of how Celeste might choose to represent a password managed by the" "SpoonPassword class." ^ ( self passwords ) at: aKey .! ! !SpoonPassword class methodsFor: 'accessing'! at: aKey put: aValue ^ ( self passwords ) at: aKey put: aValue.! ! !SpoonPassword class methodsFor: 'private' stamp: 'il prior: 34095788!!!!!!!! '! fileInPasswords | passwordFileStream | passwordFileStream _ FileStream oldFileNamed: (self vaultFileName). self fileInPasswordsFromStream: passwordFileStream. passwordFileStream close. ! ! !SpoonPassword class methodsFor: 'private' stamp: 'il prior: 34121901!!!!!!!! '! fileInPasswordsFromStream: aStream | dcryptor encryptedStream state currentLine currentChar tokens | dcryptor _ ( ARC4 new ) initialize: ( self masterKey). encryptedStream _ EncryptedStream on: aStream with: dcryptor. state _ #FirstLine. currentLine _ ''. [ encryptedStream atEnd ] whileFalse: [ "Todo: This is probably bad." currentChar _ ( ( encryptedStream next ) asCharacter ). ( ( currentChar asInteger ) = 13 ) ifFalse: [ currentLine _ currentLine , ( currentChar ) asString. ] ifTrue: [ ( state = #FirstLine ) ifTrue: [ ( currentLine = (self magicCookie) ) ifTrue: [ state _ #NotFirstLine. ] ] ifFalse: [ tokens _ currentLine findTokens: ' '. (self passwords) at: (tokens at: 1) put: (tokens at: 2). ]. currentLine _ ''. ]. ]. encryptedStream close. dcryptor clearSensitiveData.! ! !SpoonPassword class methodsFor: 'private' stamp: 'il prior: 34096052!!!!!!!! '! flushPasswordCache "write the password cache back out to the vault file." | passwordFileStream ncryptor | ncryptor _ ( ARC4 new) initialize: ( self masterKey ). passwordFileStream _ EncryptedStream on: ( FileStream newFileNamed: (self vaultFileName) ) with: ncryptor. passwordFileStream nextPutAll: (self magicCookie); cr. ( ( self passwords ) keys ) do: [ :current | passwordFileStream nextPutAll: current; nextPutAll: ' '; nextPutAll: ( self at: current ); cr. ].! ! !SpoonPassword class methodsFor: 'private' stamp: 'il prior: 34087075!!!!!!!! '! magicCookie "this is such a BAD idea. You really don't want to have magic cookies at the front" "of files encrypted with vernam ciphers." ^ '31337MagicCookie' .! ! !SpoonPassword class methodsFor: 'private' stamp: 'il prior: 34093073!!!!!!!! '! masterKey | passphrase | ( MasterKey isNil ) ifTrue: [ passphrase _ Preferences secretVaultPassword. passphrase ifNil: [ passphrase _ FillInTheBlank request: 'Vault Master Password?'. ]. self setMasterKeyFromString: passphrase. ]. ^ MasterKey .! ! !SpoonPassword class methodsFor: 'private' stamp: 'msh 11/7/2005 15:48'! passwords "Return a reference to the Passwords dictionary if it is non-nil. If it is nil, it means we" "haven't read our passwords in from the vault." "note that this is a private method. If you want to access a particular password, use the" "#at: and #at:put: methods." ( Passwords isNil ) ifTrue: [ Passwords _ Dictionary new. self fileInPasswords. ]. ^ Passwords .! ! !SpoonPassword class methodsFor: 'private' stamp: 'il prior: 34073573!!!!!!!! '! setMasterKeyFromString: aString | pbe | self clearMasterKey. pbe _ ( PasswordBasedEncryptor new ) password: aString; salt: #( 8 3 4 2 5 6 7 4 8 6 4 2 3 4 5 6 7 8 9 0 ); iteration: 50. MasterKey _ pbe pbkdf1. pbe clearSensitiveData. 1 to: ( aString size ) do: [ :current | aString at: current put: $$ ].! ! !SpoonPassword class methodsFor: 'private'! vaultFileName | fileName | fileName _ Preferences secretVaultFileName. fileName ifNil: [ fileName _ 'svault.bin'. ]. ^ fileName .! ! !SpoonPassword class methodsFor: 'eschatology' stamp: 'il prior: 34061650!!!!!!!! '! shutDown self flushPasswordCache; clearSensitiveData.! ! !SpoonPassword class methodsFor: 'sensitive data' stamp: 'il prior: 34072012!!!!!!!! '! clearMasterKey MasterKey ifNotNil: [ 1 to: (MasterKey size) do: [ :current | MasterKey at: current put: 0. ]. ]. MasterKey _ nil.! ! !SpoonPassword class methodsFor: 'sensitive data' stamp: 'msh 11/7/2005 12:01'! clearPassword: aKey "Overwrite the password referenced by the value aKey, then remove it from the passwords" "dictionary." | theString passwordDictionary | passwordDictionary _ self passwords. theString _ ( passwordDictionary at: aKey ). 1 to: ( theString size ) do: [ :current | theString at: current put: $$. ]. passwordDictionary removeKey: aKey.! ! !SpoonPassword class methodsFor: 'sensitive data' stamp: 'il prior: 34072486!!!!!!!! '! clearSensitiveData "Overwrite passwords in the Passwords dictionary, then remove the Association." ( ( self passwords ) keys ) do: [ :current | self clearPassword: current. ]. self clearMasterKey. Passwords _ nil.! ! !SpoonPassword class methodsFor: 'class initialization' stamp: 'msh 11/7/2005 18:40'! initialize Smalltalk addToShutDownList: self.! ! !SymmetricStreamCipher methodsFor: 'output size' stamp: 'msh 5/11/2005 14:40'! outputSize: anIndex ^ anIndex .! ! !SymmetricStreamCipher methodsFor: 'encryption' stamp: 'msh 5/11/2005 15:40'! decrypt: cleartext ^ self encrypt: cleartext .! ! !SymmetricStreamCipher methodsFor: 'encryption' stamp: 'msh 5/11/2005 15:40'! decrypt: cleartext into: ciphertext self encrypt: cleartext into: ciphertext .! ! !SymmetricStreamCipher methodsFor: 'encryption' stamp: 'msh 5/11/2005 15:41'! decrypt: cleartext into: ciphertext withOffset: anOffset self encrypt: cleartext into: ciphertext withOffset: anOffset.! ! !SymmetricStreamCipher methodsFor: 'encryption' stamp: 'msh 5/11/2005 15:39'! encrypt: cleartext | rv | rv _ ByteArray new: ( self outputSize: ( cleartext size ) ). self encrypt: cleartext into: rv. ^ rv .! ! !SymmetricStreamCipher methodsFor: 'encryption' stamp: 'msh 5/11/2005 15:38'! encrypt: cleartext into: ciphertext self encrypt: cleartext into: ciphertext withOffset: 0.! ! !SymmetricStreamCipher methodsFor: 'encryption' stamp: 'msh 5/11/2005 15:38'! encrypt: cleartext into: ciphertext withOffset: anOffset | keystream | keystream _ self next: ( cleartext size ) . 1 to: ( keystream size ) do: [ :index | ciphertext at: ( index + anOffset ) put: ( ( cleartext at: index ) bitXor: ( keystream at: index ) ) . ]. 1 to: ( keystream size ) do: [ :index | keystream at: index put: 0. ]! ! !ARC4 methodsFor: 'sensitive data' stamp: 'msh 5/11/2005 14:42'! clearSensitiveData i _ 0. j _ 0. 1 to: 256 do: [ :index | sbox at: index put: 0. ].! ! !ARC4 methodsFor: 'encryption' stamp: 'msh 5/11/2005 15:09'! initialize: aKey | ell jay temp | i _ 0. j _ 0. sbox _ ByteArray new: 256. 1 to: 256 do: [ :index | sbox at: index put: ( index - 1 ). ]. ell _ aKey size. jay _ 0. 0 to: 255 do: [ :index | jay _ ( jay + ( sbox at: ( index + 1 ) ) + ( aKey at: ( ( index \\ ell ) + 1 ) ) ) \\ 256. temp _ sbox at: ( index + 1). sbox at: ( index + 1 ) put: ( sbox at: ( jay + 1 ) ). sbox at: ( jay + 1 ) put: temp. ]. temp _ 0. ell _ 0. jay _ 0. ! ! !ARC4 methodsFor: 'keystream' stamp: 'msh 11/7/2005 15:34'! next | rv temp | i _ ( i + 1 ) \\ 256. j _ ( j + ( sbox at: ( i + 1) ) ) \\ 256. temp _ sbox at: ( i + 1 ). sbox at: ( i + 1 ) put: ( sbox at: ( j + 1 ) ). sbox at: ( j + 1 ) put: temp . rv _ sbox at: ( ( ( sbox at: ( i + 1 ) ) + ( sbox at: ( j + 1 ) ) ) \\ 256 ) + 1. ^ rv .! ! !ARC4 methodsFor: 'keystream' stamp: 'msh 5/11/2005 15:20'! next: aCount | rv | rv _ ByteArray new: aCount. self next: aCount into: rv. ^ rv .! ! !ARC4 methodsFor: 'keystream' stamp: 'msh 5/11/2005 15:12'! next: aCount into: anArray 1 to: aCount do: [ :count | anArray at: count put: ( self next ). ].! ! SpoonPassword initialize! !SpoonPassword class reorganize! ('accessing' at: at:put:) ('private' fileInPasswords fileInPasswordsFromStream: flushPasswordCache magicCookie masterKey passwords setMasterKeyFromString: vaultFileName) ('eschatology' shutDown) ('sensitive data' clearMasterKey clearPassword: clearSensitiveData) ('class initialization' initialize) ! SHA256 initialize! SHA1 initialize! MD5 initialize! MD2 initialize! MessageDigest initialize!