From VisualWorks®, 7.6 of February 1, 2008 on February 1, 2008 at 12:31:49 pm (Dialog confirm: 'You are filing-in a Parcel source file!\\While this is possible it will not have\the same effect as loading the parcel.\None of the Parcel''s prerequisites will\be loaded and none of its load actions\will be performed.\\Are you sure you want to file-in?' withCRs) ifFalse: [self error: 'Parcel file-in abandoned. Choose terminate or close.'] <class> <name>PBC</name> <environment>Security</environment> <super>Core.Object</super> <private>false</private> none count v1 prf cipher mac defaultCount <imports></imports> <category>PBC</category> <attributes> <package>PKCS5</package> </attributes> </class> <comment> Security.PBC
A preconfigured instance of this class can generate keys based on selected key derivation function (KDF) and either provide encryption or signing services. The standard defines a number of configurations in the Appendix A, some of them are expressed in the form of instance creation methods. The selectors follow the naming conventions used in the standard. As the standard points out, configurations based on the earlier version of the key derivation function "pkdf1" (these are indicated by the v1 instance variable) are not recommended for new applications and are included only for compatibility with existing applications. Here is a simple example of how to use the algorithm for encryption. First create and configure and algorithm instance pbc := PBC pbes2WithHMAC_SHA1AndDES_EDE3_CBC. Now we can encrypt a message using a salt and password: msg := 'Message in a Bottle' asByteArray. pwd := 'This is the end of the world ...' asByteArray. salt := 'A randomly generated sequence of bytes' asByteArray. ciphertext := pbc encrypt: msg password: pwd salt: salt. Message can be decrypted as follows: plaintext := pbc decrypt: ciphertext password: pwd salt: salt. If there is no suitable random generator available to generate the salt value, the standard proposes a deterministic scheme for salt generation based on the provided message and the password. This functionality is also available in a modified version of the encryption API, which returns both the generated salt and the ciphertext as an association. saltAndCiphertext := pbc encrypt: msg password: pwd. salt := saltAndCiphertext key. ciphertext := saltAndCiphertext value. The decryption API remains the same. Note that the salt value must be transferred along with the ciphertext as the recipient has no way to determine the correct salt value even though she knows the password. Also note that this salt generation scheme is not suitable for all applications (refer to the standard for more details). The algorithm instance has to be configured differently for signing. Here is an example. pbc := PBC pbmac1WithHMAC_SHA1AndHMAC_SHA1. saltAndSignature := pbc sign: msg password: pwd. salt := saltAndSignature key. signature := saltAndSignature value. And here is how to verify a signature pbc verify: signature of: msg password: pwd salt: salt. Instance Variables: count <Integer> iteration count, default 1000 v1 <Boolean> use version 1 of the algorithms prf <MessageDigest> a hash algorithm instance used by the key derivation function (KDF) cipher <BlockCipher> a cipher algorithm used by the encryption API mac <HMAC> a message authentication algorithm used by the signing API Class Instance Variables: defaultCount <Integer> the default iteration count
</comment> <methods> Security.PBC <category>constants</category>
DES_CBC ^DES newBP_CBC
DES_EDE3_CBC ^DES newBP_3EDE_CBC
HMAC_SHA1 ^HMAC new setHash: SHA new
MD5 ^MD5 new
SHA1 ^SHA new
</methods> <methods> Security.PBC <category>private</category>
keySize ^cipher pkcs5KeySize
</methods> <methods> Security.PBC <category>private-pkcs5</category>
pbes1PrepareFor: message password: password salt: salt | dk keySize | keySize := self keySize. dk := self pbkdf1Password: password salt: salt count: self count length: keySize + cipher blockSize. cipher setKey: (dk copyFrom: 1 to: keySize); setIV: (dk copyFrom: keySize + 1 to: dk size)
pbes2PrepareFor: message password: password salt: salt | dk keySize | keySize := self keySize. dk := self pbkdf2Password: password salt: salt count: self count length: keySize + cipher blockSize. cipher setKey: (dk copyFrom: 1 to: keySize); setIV: (dk copyFrom: keySize + 1 to: dk size)
pbkdf1Password: password salt: salt count: iterationCount length: keyLength | t | keyLength > prf digestSize ifTrue: [ self error: 'Derived key too long' ]. t := prf hash: password, salt. iterationCount - 1 timesRepeat: [ t := prf hash: t ]. ^t copyFrom: 1 to: keyLength
pbkdf2Password: password salt: salt count: iterationCount length: keyLength | hLen position i dk| hLen := prf digestSize. keyLength > "2**32 - 1" (4294967295 * hLen) ifTrue: [ self error: 'Derived key too long' ]. dk := ByteArray new: keyLength. position := 1. i := 1. prf setKey: password. [ position > keyLength ] whileFalse: [ | u t | u := salt, i asBigEndianByteArray. t := ByteArray new: hLen. iterationCount timesRepeat: [ u := prf hash: u. 1 to: hLen do: [ :j | t at: j put: ((t at: j) bitXor: (u at: j)) ]]. dk replaceFrom: position to: (position + hLen - 1 min: keyLength) with: t startingAt: 1. position := position + hLen. i := i + 1 ]. ^dk
pbmac1PrepareFor: message password: password salt: salt keyLength: keyLength | dk s dkLen | s := salt ifNil: [ self saltFrom: message password: password ]. dkLen := keyLength ifNil: [ mac blockSize ]. dk := self pbkdf2Password: password salt: s count: self count length: dkLen. mac setKey: dk
saltFrom: message password: password "Generates a salt deterministicly, as described in the final Note of section 4.1, PKCS #5, v2.0" ^self key: 8 password: password salt: message
</methods> <methods> Security.PBC <category>initialize-release</category>
pbes2WithHMAC_SHA1AndDES_CBC v1 := false. self setPrf: self HMAC_SHA1; setCipher: self DES_CBC
pbes2WithHMAC_SHA1AndDES_EDE3_CBC v1 := false. self setPrf: self HMAC_SHA1; setCipher: self DES_EDE3_CBC
pbeWithMD5AndDES_CBC v1 := true. self setPrf: self MD5; setCipher: self DES_CBC
pbeWithSHA1AndDES_CBC v1 := true. self setPrf: self SHA1; setCipher: self DES_CBC
pbmac1WithHMAC_SHA1AndHMAC_SHA1 v1 := false. self setPrf: self HMAC_SHA1; setMac: self HMAC_SHA1
setCipher: aBlockCipher cipher := aBlockCipher
setMac: aMac mac := aMac
setPrf: aHash prf := aHash
</methods> <methods> Security.PBC <category>services</category>
decrypt: message password: password salt: salt "Decrypts message using password and salt. message <ByteArray> the encrypted message password <ByteArray> usually UTF-8 or ASCII encoded secret text salt <ByteArray> not secret, but randomly generated byte sequence (at least 8 bytes); additional requirements may apply ^<ByteArray> the decrypted message" v1 ifTrue: [ self pbes1PrepareFor: message password: password salt: salt ] ifFalse: [ self pbes2PrepareFor: message password: password salt: salt ]. ^cipher decrypt: message
encrypt: message password: password "Encrypt message using password and deterministicly generated salt. message <ByteArray> message to be encrypted password <ByteArray> usually UTF-8 or ASCII encoded secret text ^<ByteArray -> ByteArray> generated salt value with the encrypted message" | salt ct | salt := self saltFrom: message password: password. ct := self encrypt: message password: password salt: salt. ^salt -> ct
encrypt: message password: password salt: salt "Encrypts message using password and salt. message <ByteArray> message to be encrypted password <ByteArray> usually UTF-8 or ASCII encoded secret text salt <ByteArray> not secret, but randomly generated byte sequence (at least 8 bytes); additional requirements may apply ^<ByteArray> the encrypted message" v1 ifTrue: [ self pbes1PrepareFor: message password: password salt: salt ] ifFalse: [ self pbes2PrepareFor: message password: password salt: salt ]. ^cipher encrypt: message
key: keyLength password: password salt: salt "Generate a key using pasword and salt. keyLength <anInteger> desired byte length of the key (constraints are imposed by the underlying KDF) password <ByteArray> usually UTF-8 or ASCII encoded secret text salt <ByteArray> not secret, but randomly generated byte sequence (at least 8 bytes); additional requirements may apply ^<ByteArray> a key of desired length" ^v1 ifTrue: [ self pbkdf1Password: password salt: salt count: self count length: keyLength ] ifFalse: [ self pbkdf2Password: password salt: salt count: self count length: keyLength ]
sign: message password: password "Generate message signature using password and a deterministically generated salt. message <ByteArray> the message to be signed password <ByteArray> usually UTF-8 or ASCII encoded secret text ^<ByteArray -> ByteArray> the generated salt value with the message signature" | salt signature | salt := self saltFrom: message password: password. signature := self sign: message password: password salt: salt. ^salt -> signature
sign: message password: password salt: salt "Generate message signature using password and salt to generate key of optimal length. message <ByteArray> the message to be signed password <ByteArray> usually UTF-8 or ASCII encoded secret text salt <ByteArray> not secret, but randomly generated byte sequence (at least 8 bytes); additional requirements may apply ^<ByteArray> the message signature" ^self sign: message password: password salt: salt keyLength: mac blockSize
sign: message password: password salt: salt keyLength: length "Generate message signature using password and salt to generate key of specified length. message <ByteArray> the message to be signed password <ByteArray> usually UTF-8 or ASCII encoded secret text salt <ByteArray> not secret, but randomly generated byte sequence (at least 8 bytes); additional requirements may apply length <Integer> desired byte length of the key to be used ^<ByteArray> the message signature" self pbmac1PrepareFor: message password: password salt: salt keyLength: length. ^mac hash: message
verify: signature of: message password: password "Verifies message signature using password and deterministicly generated salt. signature <ByteArray> the message signature message <ByteArray> the signed message password <ByteArray> usually UTF-8 or ASCII encoded secret text ^<Boolean> signature validity" | salt | salt := self saltFrom: message password: password. ^self verify: signature of: message password: password salt: salt
verify: signature of: message password: password salt: salt "Verifies message signature using password and salt to generate key of optimal length. signature <ByteArray> the message signature message <ByteArray> the signed message password <ByteArray> usually UTF-8 or ASCII encoded secret text salt <ByteArray> not secret, but randomly generated byte sequence (at least 8 bytes); additional requirements may apply ^<Boolean> signature validity" ^self verify: signature of: message password: password salt: salt keyLength: mac blockSize
verify: signature of: message password: password salt: salt keyLength: length "Verifies message signature using password and salt to generate key of specified length. signature <ByteArray> the message signature message <ByteArray> the signed message password <ByteArray> usually UTF-8 or ASCII encoded secret text salt <ByteArray> not secret, but randomly generated byte sequence (at least 8 bytes); additional requirements may apply length <Integer> desired byte length of the key to be used ^<Boolean> signature validity" self pbmac1PrepareFor: message password: password salt: salt keyLength: length. ^signature = (mac hash: message)
</methods> <methods> Security.PBC <category>accessing</category>
count ^count ifNil: [ self class defaultCount ]
count: anInteger "The standard recommend 1000 as the minimum value for the iteration count. Optimal value depends on the computational power of hardware throughout the lifecycle of the protected information. Generally it should be low enough to avoid unacceptable delays for the user but otherwise as high as possible to maximize the detrimental effect on search attacks." count := anInteger
</methods> <methods> Security.PBC class <category>instance creation</category>
pbes2WithHMAC_SHA1AndDES_CBC ^self new pbes2WithHMAC_SHA1AndDES_CBC
pbes2WithHMAC_SHA1AndDES_EDE3_CBC ^self new pbes2WithHMAC_SHA1AndDES_EDE3_CBC
pbeWithMD5AndDES_CBC ^self new pbeWithMD5AndDES_CBC
pbeWithSHA1AndDES_CBC ^self new pbeWithSHA1AndDES_CBC
pbmac1WithHMAC_SHA1AndHMAC_SHA1 ^self new pbmac1WithHMAC_SHA1AndHMAC_SHA1
</methods> <methods> Security.PBC class <category>accessing</category>
defaultCount " ^<Integer> default iteration count " ^defaultCount ifNil: [ self defaultCountValue ]
defaultCount: count " count <Integer> default iteration count " defaultCount := count
defaultCountValue "This is the minimum value recommended by the standard." ^1000
</methods> <methods> Security.CipherBlockChaining <category>pkcs5</category>
pkcs5KeySize ^cipher pkcs5KeySize
</methods> <methods> Security.BlockPadding <category>pkcs5</category>
pkcs5KeySize ^cipher pkcs5KeySize
</methods> <methods> Security.TripleEDE <category>pkcs5</category>
pkcs5KeySize ^cipher pkcs5KeySize * 3
</methods> <methods> Security.DES <category>pkcs5</category>
pkcs5KeySize ^8
</methods> "Imported Classes:" self error: 'Attempting to file-in parcel imports. Choose terminate or close' <class> <name>Object</name> <environment>Core</environment> <super></super> <private>false</private> none <imports></imports> <category>Kernel-Objects</category> <attributes> <package>Kernel-Objects</package> </attributes> </class> <class> <name>BlockPadding</name> <environment>Security</environment> <super>Security.BlockCipherPadding</super> <private>false</private> none <imports></imports> <category>Security-Ciphers</category> <attributes> <package>CiphersBase</package> </attributes> </class> <class> <name>TripleEDE</name> <environment>Security</environment> <super>Security.BlockCipherMode</super> <private>false</private> none cipher2 cipher3 <imports></imports> <category>Security-Ciphers</category> <attributes> <package>CiphersBase</package> </attributes> </class> <class> <name>CipherBlockChaining</name> <environment>Security</environment> <super>Security.BlockCipherMode</super> <private>false</private> none iv ivBackup <imports></imports> <category>Security-Ciphers</category> <attributes> <package>CiphersBase</package> </attributes> </class> <class> <name>DES</name> <environment>Security</environment> <super>Security.BlockCipher</super> <private>false</private> none ignoreParity checkForWeakKey keySchedule encryptInPlace helperU helperT helper registerR registerU registerT registerL spRegisterTransformation skbTransformation spRegisterTransformation1 spRegisterTransformation2 spRegisterTransformation2ScratchRegister spRegisterTransformation3 spRegisterTransformation4 spRegisterTransformation5 spRegisterTransformation6 spRegisterTransformation7 spRegisterTransformation8 skbRegisterTransformation alternateShiftSequence reg arrayClass byteArrayClass largePositiveIntegerClass largePositiveScratchIntR largePositiveScratchIntU registerClass desHelperClass arrayClass byteArrayClass largePositiveIntegerClass spRegisterTransformation skbTransformation skbRegisterTransformation alternateShiftSequence <imports></imports> <category>Security-Ciphers</category> <attributes> <package>DES</package> </attributes> </class>