!DESPlugin class methodsFor: 'translation' stamp: 'DSM 1/26/2000 00:06' prior: 41780650! declareCVarsIn: cg cg var: 'byteBit' declareC: 'unsigned short byteBit[8] = { 128,64,32,16,8,4,2,1 }'. cg var: 'bigByte' declareC: (String streamContents:[:s| s nextPutAll:'unsigned long bigByte[24] = { '. 23 to: 0 by: -1 do: [ :i | s nextPutAll: (1<). Each key is an array of four large integers. The private key is (p, q, g, x); the public one is (p, q, g, y). The signer must be sure to record (p, q, g, x), and must keep x secret to prevent someone from forging their signature." "Note: Key generation can take some time. Open a transcript so you can see what's happening and take a coffee break!!" | exp h | random _ SecureRandom new. self generateQandP. exp _ (p - 1) / q. h _ 2. [g _ h raisedTo: exp modulo: p. g = 1] whileTrue: [h _ h + 1]. x _ self nextRandom160. y _ g raisedTo: x modulo: p. ! ! !DSAKeyPairGenerator methodsFor: 'as yet unclassified' stamp: 'len 10/25/2002 15:14' prior: 41789805! generateQandP "Generate the two industrial-grade primes, q (160-bits) and p (512-bit) needed to build a key set. Answer the array (q, p, s), where s is the seed that from which q and p were created. This seed is normally discarded, but can be used to verify the key generation process if desired." | pBits halfTwoToTheP chunkCount twoQ n c w | pBits _ 512. "desired size of p in bits" halfTwoToTheP _ 2 raisedTo: (pBits - 1). chunkCount _ pBits // 160. Transcript show: 'Searching for primes q and p...'; cr. [true] whileTrue: [ Transcript show: ' Found a candidate q.'; cr. q _ random nextBits: 160. q _ q bitOr: 1. "ensure it is odd" q _ q bitOr: 1 << 160. "ensure it is of the requiered length" q _ (PrimesFinder candidate: q) nextPrime. twoQ _ q bitShift: 1. n _ 2. c _ 0. [c < 4096] whileTrue: [ w _ random nextBits: pBits. x _ w + halfTwoToTheP. p _ (x - ( x \\ twoQ)) + 1. p highBit = pBits ifTrue: [ Transcript show: ' Testing potential p ', (c + 1) printString, '...'; cr. (self isProbablyPrime: p) ifTrue: [ Transcript show: ' Found p!!'; cr. ^ self]]. n _ n + chunkCount + 1. c _ c + 1]]! ! !DSAKeyPairGenerator methodsFor: 'as yet unclassified' stamp: 'len 8/15/2002 02:23' prior: 41791062! privateKey ^ DSAPrivateKey p: p q: q g: g x: x! ! !DSAKeyPairGenerator methodsFor: 'as yet unclassified' stamp: 'len 8/15/2002 02:24' prior: 41791198! publicKey ^ DSAPublicKey p: p q: q g: g y: y! ! !DSAPlugin methodsFor: 'primitives-SHA' stamp: 'jm 12/21/1999 22:52' prior: 41791317! primitiveExpandBlock "Expand a 64 byte ByteArray (the first argument) into and an Bitmap of 80 32-bit words (the second argument). When reading a 32-bit integer from the ByteArray, consider the first byte to contain the most significant bits of the word (i.e., use big-endian byte ordering)." | expanded buf wordPtr bytePtr src v | self export: true. self var: #wordPtr declareC: 'unsigned int *wordPtr'. self var: #bytePtr declareC: 'unsigned char *bytePtr'. expanded _ interpreterProxy stackObjectValue: 0. buf _ interpreterProxy stackObjectValue: 1. interpreterProxy success: (interpreterProxy isWords: expanded). interpreterProxy success: (interpreterProxy isBytes: buf). interpreterProxy failed ifTrue: [^ nil]. interpreterProxy success: ((interpreterProxy stSizeOf: expanded) = 80). interpreterProxy success: ((interpreterProxy stSizeOf: buf) = 64). interpreterProxy failed ifTrue: [^ nil]. wordPtr _ interpreterProxy firstIndexableField: expanded. bytePtr _ interpreterProxy firstIndexableField: buf. src _ 0. 0 to: 15 do: [:i | v _ ((bytePtr at: src) << 24) + ((bytePtr at: src + 1) << 16) + ((bytePtr at: src + 2) << 8) + (bytePtr at: src + 3). wordPtr at: i put: v. src _ src + 4]. 16 to: 79 do: [:i | v _ (((wordPtr at: i - 3) bitXor: (wordPtr at: i - 8)) bitXor: (wordPtr at: i - 14)) bitXor: (wordPtr at: i - 16). v _ self leftRotate: v by: 1. wordPtr at: i put: v]. interpreterProxy pop: 2. ! ! !DSAPlugin methodsFor: 'primitives-SHA' stamp: 'jm 12/21/1999 20:43' prior: 41792855! primitiveHasSecureHashPrimitive "Answer true if the secure hash primitive is implemented." self export: true. interpreterProxy pop: 1. interpreterProxy pushBool: true. ! ! !DSAPlugin methodsFor: 'primitives-SHA' stamp: 'jm 12/21/1999 23:35' prior: 41793102! primitiveHashBlock "Hash a Bitmap of 80 32-bit words (the first argument), using the given state (the second argument)." | state buf statePtr bufPtr a b c d e tmp | self export: true. self var: #statePtr declareC: 'unsigned int *statePtr'. self var: #bufPtr declareC: 'unsigned int *bufPtr'. state _ interpreterProxy stackObjectValue: 0. buf _ interpreterProxy stackObjectValue: 1. interpreterProxy success: (interpreterProxy isWords: state). interpreterProxy success: (interpreterProxy isWords: buf). interpreterProxy failed ifTrue: [^ nil]. interpreterProxy success: ((interpreterProxy stSizeOf: state) = 5). interpreterProxy success: ((interpreterProxy stSizeOf: buf) = 80). interpreterProxy failed ifTrue: [^ nil]. statePtr _ interpreterProxy firstIndexableField: state. bufPtr _ interpreterProxy firstIndexableField: buf. a _ statePtr at: 0. b _ statePtr at: 1. c _ statePtr at: 2. d _ statePtr at: 3. e _ statePtr at: 4. 0 to: 19 do: [:i | tmp _ 16r5A827999 + ((b bitAnd: c) bitOr: (b bitInvert32 bitAnd: d)) + (self leftRotate: a by: 5) + e + (bufPtr at: i). e _ d. d _ c. c _ self leftRotate: b by: 30. b _ a. a _ tmp]. 20 to: 39 do: [:i | tmp _ 16r6ED9EBA1 + ((b bitXor: c) bitXor: d) + (self leftRotate: a by: 5) + e + (bufPtr at: i). e _ d. d _ c. c _ self leftRotate: b by: 30. b _ a. a _ tmp]. 40 to: 59 do: [:i | tmp _ 16r8F1BBCDC + (((b bitAnd: c) bitOr: (b bitAnd: d)) bitOr: (c bitAnd: d)) + (self leftRotate: a by: 5) + e + (bufPtr at: i). e _ d. d _ c. c _ self leftRotate: b by: 30. b _ a. a _ tmp]. 60 to: 79 do: [:i | tmp _ 16rCA62C1D6 + ((b bitXor: c) bitXor: d) + (self leftRotate: a by: 5) + e + (bufPtr at: i). e _ d. d _ c. c _ self leftRotate: b by: 30. b _ a. a _ tmp]. statePtr at: 0 put: (statePtr at: 0) + a. statePtr at: 1 put: (statePtr at: 1) + b. statePtr at: 2 put: (statePtr at: 2) + c. statePtr at: 3 put: (statePtr at: 3) + d. statePtr at: 4 put: (statePtr at: 4) + e. interpreterProxy pop: 2. ! ! !DSAPlugin methodsFor: 'primitives-integers' stamp: 'jm 12/21/1999 18:48' prior: 41795209! primitiveBigDivide "Called with three LargePositiveInteger arguments, rem, div, quo. Divide div into rem and store the quotient into quo, leaving the remainder in rem." "Assume: quo starts out filled with zeros." | rem div quo | self export: true. quo _ interpreterProxy stackObjectValue: 0. div _ interpreterProxy stackObjectValue: 1. rem _ interpreterProxy stackObjectValue: 2. interpreterProxy success: (interpreterProxy fetchClassOf: rem) = interpreterProxy classLargePositiveInteger. interpreterProxy success: (interpreterProxy fetchClassOf: div) = interpreterProxy classLargePositiveInteger. interpreterProxy success: (interpreterProxy fetchClassOf: quo) = interpreterProxy classLargePositiveInteger. interpreterProxy failed ifTrue:[^ nil]. dsaRemainder _ interpreterProxy firstIndexableField: rem. dsaDivisor _ interpreterProxy firstIndexableField: div. dsaQuotient _ interpreterProxy firstIndexableField: quo. divisorDigitCount _ interpreterProxy stSizeOf: div. remainderDigitCount _ interpreterProxy stSizeOf: rem. "adjust pointers for base-1 indexing" dsaRemainder _ dsaRemainder - 1. dsaDivisor _ dsaDivisor - 1. dsaQuotient _ dsaQuotient - 1. self bigDivideLoop. interpreterProxy pop: 3. ! ! !DSAPlugin methodsFor: 'primitives-integers' stamp: 'jm 12/21/1999 08:09' prior: 41796522! primitiveBigMultiply "Multiple f1 by f2, placing the result into prod. f1, f2, and prod must be LargePositiveIntegers, and the length of prod must be the sum of the lengths of f1 and f2." "Assume: prod starts out filled with zeros" | prod f2 f1 prodLen f1Len f2Len prodPtr f2Ptr f1Ptr digit carry k sum | self export: true. self var: #prodPtr declareC: 'unsigned char *prodPtr'. self var: #f2Ptr declareC: 'unsigned char *f2Ptr'. self var: #f1Ptr declareC: 'unsigned char *f1Ptr'. prod _ interpreterProxy stackObjectValue: 0. f2 _ interpreterProxy stackObjectValue: 1. f1 _ interpreterProxy stackObjectValue: 2. interpreterProxy success: (interpreterProxy isBytes: prod). interpreterProxy success: (interpreterProxy isBytes: f2). interpreterProxy success: (interpreterProxy isBytes: f1). interpreterProxy success: (interpreterProxy fetchClassOf: prod) = interpreterProxy classLargePositiveInteger. interpreterProxy success: (interpreterProxy fetchClassOf: f2) = interpreterProxy classLargePositiveInteger. interpreterProxy success: (interpreterProxy fetchClassOf: f1) = interpreterProxy classLargePositiveInteger. interpreterProxy failed ifTrue:[^ nil]. prodLen _ interpreterProxy stSizeOf: prod. f1Len _ interpreterProxy stSizeOf: f1. f2Len _ interpreterProxy stSizeOf: f2. interpreterProxy success: (prodLen = (f1Len + f2Len)). interpreterProxy failed ifTrue:[^ nil]. prodPtr _ interpreterProxy firstIndexableField: prod. f2Ptr _ interpreterProxy firstIndexableField: f2. f1Ptr _ interpreterProxy firstIndexableField: f1. 0 to: f1Len-1 do: [:i | (digit _ f1Ptr at: i) ~= 0 ifTrue: [ carry _ 0. k _ i. "Loop invariants: 0 <= carry <= 16rFF, k = i + j - 1" 0 to: f2Len-1 do: [:j | sum _ ((f2Ptr at: j) * digit) + (prodPtr at: k) + carry. carry _ sum bitShift: -8. prodPtr at: k put: (sum bitAnd: 255). k _ k + 1]. prodPtr at: k put: carry]]. interpreterProxy pop: 3. ! ! !DSAPlugin methodsFor: 'primitives-integers' stamp: 'jm 12/21/1999 09:31' prior: 41798542! primitiveHighestNonZeroDigitIndex "Called with one LargePositiveInteger argument. Answer the index of the top-most non-zero digit." | arg bigIntPtr i | self export: true. self var: #bigIntPtr declareC: 'unsigned char *bigIntPtr'. arg _ interpreterProxy stackObjectValue: 0. interpreterProxy success: (interpreterProxy fetchClassOf: arg) = interpreterProxy classLargePositiveInteger. interpreterProxy failed ifTrue: [^ nil]. bigIntPtr _ interpreterProxy firstIndexableField: arg. i _ interpreterProxy stSizeOf: arg. [(i > 0) and: [(bigIntPtr at: (i _ i - 1)) = 0]] whileTrue: ["scan down from end to first non-zero digit"]. interpreterProxy pop: 1. interpreterProxy pushInteger: i + 1. ! ! !DSAPlugin methodsFor: 'private' stamp: 'jm 12/21/1999 08:10' prior: 41799314! addBackDivisorDigitShift: digitShift "Add back the divisor shifted left by the given number of digits. This is done only when the estimate of quotient digit was one larger than the correct value." | carry rIndex sum | carry _ 0. rIndex _ digitShift + 1. 1 to: divisorDigitCount do: [:i | sum _ (dsaRemainder at: rIndex) + (dsaDivisor at: i) + carry. dsaRemainder at: rIndex put: (sum bitAnd: 16rFF). carry _ sum bitShift: -8. rIndex _ rIndex + 1]. "do final carry" sum _ (dsaRemainder at: rIndex) + carry. dsaRemainder at: rIndex put: (sum bitAnd: 16rFF). "Note: There should be a final carry that cancels out the excess borrow." "Assert: (sum bitShift: -8) ~= 1 ifTrue: [self halt: 'no carry!!']." ! ! !DSAPlugin methodsFor: 'private' stamp: 'jm 12/21/1999 18:48' prior: 41800101! bigDivideLoop "This is the core of the divide algorithm. This loop steps through the digit positions of the quotient, each time estimating the right quotient digit, subtracting from the remainder the divisor times the quotient digit shifted left by the appropriate number of digits. When the loop terminates, all digits of the quotient have been filled in and the remainder contains a value less than the divisor. The tricky bit is estimating the next quotient digit. Knuth shows that the digit estimate computed here will never be less than it should be and cannot be more than one over what it should be. Furthermore, the case where the estimate is one too large is extremely rare. For example, in a typical test of 100000 random 60-bit division problems, the rare case only occured five times. See Knuth, volume 2 ('Semi-Numerical Algorithms') 2nd edition, pp. 257-260" | d1 d2 firstDigit firstTwoDigits thirdDigit q digitShift qTooBig | "extract the top two digits of the divisor" d1 _ dsaDivisor at: divisorDigitCount. d2 _ dsaDivisor at: divisorDigitCount - 1. remainderDigitCount to: divisorDigitCount + 1 by: -1 do: [:j | "extract the top several digits of remainder." firstDigit _ dsaRemainder at: j. firstTwoDigits _ (firstDigit bitShift: 8) + (dsaRemainder at: j - 1). thirdDigit _ dsaRemainder at: j - 2. "estimate q, the next digit of the quotient" firstDigit = d1 ifTrue: [q _ 255] ifFalse: [q _ firstTwoDigits // d1]. "adjust the estimate of q if necessary" (d2 * q) > (((firstTwoDigits - (q * d1)) bitShift: 8) + thirdDigit) ifTrue: [ q _ q - 1. (d2 * q) > (((firstTwoDigits - (q * d1)) bitShift: 8) + thirdDigit) ifTrue: [ q _ q - 1]]. digitShift _ j - divisorDigitCount - 1. q > 0 ifTrue: [ qTooBig _ self subtractDivisorMultipliedByDigit: q digitShift: digitShift. qTooBig ifTrue: [ "this case is extremely rare" self addBackDivisorDigitShift: digitShift. q _ q - 1]]. "record this digit of the quotient" dsaQuotient at: digitShift + 1 put: q]. ! ! !DSAPlugin methodsFor: 'private' stamp: 'jm 12/21/1999 21:54' prior: 41802200! leftRotate: anInteger by: bits "Rotate the given 32-bit integer left by the given number of bits and answer the result." self var: #anInteger declareC: 'unsigned int anInteger'. ^ (anInteger << bits) bitOr: (anInteger >> (32 - bits)) ! ! !DSAPlugin methodsFor: 'private' stamp: 'jm 12/21/1999 08:13' prior: 41802505! subtractDivisorMultipliedByDigit: digit digitShift: digitShift "Multiply the divisor by the given digit (an integer in the range 0..255), shift it left by the given number of digits, and subtract the result from the current remainder. Answer true if there is an excess borrow, indicating that digit was one too large. (This case is quite rare.)" | borrow rIndex prod resultDigit | borrow _ 0. rIndex _ digitShift + 1. 1 to: divisorDigitCount do: [:i | prod _ ((dsaDivisor at: i) * digit) + borrow. borrow _ prod bitShift: -8. resultDigit _ (dsaRemainder at: rIndex) - (prod bitAnd: 16rFF). resultDigit < 0 ifTrue: [ "borrow from the next digit" resultDigit _ resultDigit + 256. borrow _ borrow + 1]. dsaRemainder at: rIndex put: resultDigit. rIndex _ rIndex + 1]. "propagate the final borrow if necessary" borrow = 0 ifTrue: [^ false]. resultDigit _ (dsaRemainder at: rIndex) - borrow. resultDigit < 0 ifTrue: [ "digit was too large (this case is quite rare)" dsaRemainder at: rIndex put: resultDigit + 256. ^ true] ifFalse: [ dsaRemainder at: rIndex put: resultDigit. ^ false]. ! ! !DSAPlugin class methodsFor: 'plugin translation' stamp: 'sma 3/3/2000 12:44' prior: 41803714! declareCVarsIn: cg cg var: #dsaRemainder type: #'unsigned char*'. cg var: #dsaDivisor type: #'unsigned char*'. cg var: #dsaQuotient type: #'unsigned char*'! ! !DSAPlugin class methodsFor: 'plugin translation' stamp: 'ar 5/15/2000 22:51' prior: 41803956! moduleName "Time millisecondsToRun: [ DSAPlugin translateDoInlining: true]" ^ 'DSAPrims' "Yes - it needs to be named this way or else we'll not find it" ! ! !DSAPrivateKey methodsFor: 'as yet unclassified' stamp: 'len 11/15/2002 23:18' prior: 41804198! computeSignatureForMessageHash: hash "Answer the digital signature of the given message hash using the given private key. A signature is a pair of large integers." | r s k tmp | r _ s _ 0. [r = 0 or: [s = 0]] whileTrue: [ k _ self nextRandom160 \\ q. r _ (g raisedTo: k modulo: p) \\ q. tmp _ (hash asInteger + (x * r)) \\ q. s _ (k inverseModulo: q) * tmp \\ q]. ^ Array with: r with: s! ! !DSAPrivateKey methodsFor: 'as yet unclassified' stamp: 'len 11/15/2002 23:18' prior: 41804683! nextRandom160 ^ (RandomPool default next: 20) asInteger! ! !DSAPrivateKey methodsFor: 'as yet unclassified' stamp: 'len 8/15/2002 02:20' prior: 41804822! p: p0 q: q0 g: g0 x: x0 p _ p0. q _ q0. g _ g0. x _ x0! ! !DSAPrivateKey methodsFor: 'as yet unclassified' stamp: 'len 11/15/2002 23:04' prior: 41804964! signMessage: aStringOrStream | hasher h sig | hasher _ SHA1 new. (aStringOrStream class isBytes) ifTrue: [h _ hasher hashMessage: aStringOrStream] ifFalse: [h _ hasher hashStream: aStringOrStream]. sig _ self computeSignatureForMessageHash: h. ^ self signatureToString: sig! ! !DSAPrivateKey methodsFor: 'as yet unclassified' stamp: 'len 11/15/2002 23:01' prior: 41805331! signatureToString: aSignature "Answer a string representation of the given signature. This string can be parsed using the stringToSignature: method." | s hex | s _ WriteStream on: (String new: 2000). s nextPutAll: '[DSA digital signature '. hex _ aSignature first printStringBase: 16. s nextPutAll: (hex copyFrom: 4 to: hex size). s space. hex _ aSignature second printStringBase: 16. s nextPutAll: (hex copyFrom: 4 to: hex size). s nextPutAll: ']'. ^ s contents! ! !DSAPrivateKey class methodsFor: 'instance creation' stamp: 'len 8/15/2002 02:19' prior: 41805892! p: p q: q g: g x: x ^ self new p: p q: q g: g x: x! ! !DSAPublicKey methodsFor: 'as yet unclassified' stamp: 'rww 1/13/2003 22:50' prior: 41806025! base64CryptoHash | encoded hash | encoded := self encodeAsnDer. ((encoded first bitAnd: 16r80) > 0) ifTrue: [encoded := #(0) asByteArray, encoded]. hash := (SHA1 hashMessage: encoded) asByteArray reversed. ((hash first bitAnd: 16r80) > 0) ifTrue: [hash := #(0) asByteArray, hash]. ^ hash toEBase64String ! ! !DSAPublicKey methodsFor: 'as yet unclassified' stamp: 'rww 1/2/2003 02:19' prior: 41806421! dssSig ^ OrderedCollection with: p with: q with: g! ! !DSAPublicKey methodsFor: 'as yet unclassified' stamp: 'rww 1/2/2003 02:22' prior: 41806554! encodeAsnDer | algorithm keyInfo | algorithm := OrderedCollection with: (ASN1ObjectId fromString: '1.2.840.10040.4.1') with: self dssSig. keyInfo := OrderedCollection with: algorithm with: self subjectPublicKey. ^ keyInfo encodeAsnDer. ! ! !DSAPublicKey methodsFor: 'as yet unclassified' stamp: 'len 8/15/2002 02:20' prior: 41806883! p: p0 q: q0 g: g0 y: y0 p _ p0. q _ q0. g _ g0. y _ y0! ! !DSAPublicKey methodsFor: 'as yet unclassified' stamp: 'len 8/15/2002 02:13' prior: 41807023! stringToSignature: aString "Answer the signature stored in the given string. A signature string has the format: '[DSA digital signature ]' where and are large positive integers represented by strings of hexidecimal digits." | prefix stream r s | prefix _ '[DSA digital signature '. (aString beginsWith: prefix) ifFalse: [self error: 'bad signature prefix']. stream _ ReadStream on: aString. stream position: prefix size. r _ Integer readFrom: stream base: 16. stream next. s _ Integer readFrom: stream base: 16. ^ Array with: r with: s ! ! !DSAPublicKey methodsFor: 'as yet unclassified' stamp: 'rww 1/2/2003 02:20' prior: 41807672! subjectPublicKey ^ ASN1BitString fromByteArray: y encodeAsnDer! ! !DSAPublicKey methodsFor: 'as yet unclassified' stamp: 'len 8/15/2002 02:17' prior: 41807818! verify: signatureString isSignatureOf: aStringOrStream "Answer true if the given signature string signs the given message (a stream or string)." "Note: Random numbers are not needed for signature verification; thus, there is no need to call initRandomFromUser before verifying a signature." | hasher h sig | hasher _ SHA1 new. (aStringOrStream class isBytes) ifTrue: [h _ hasher hashMessage: aStringOrStream] ifFalse: [h _ hasher hashStream: aStringOrStream]. sig _ self stringToSignature: signatureString. ^ self verifySignature: sig ofMessageHash: h! ! !DSAPublicKey methodsFor: 'as yet unclassified' stamp: 'len 11/15/2002 23:23' prior: 41808464! verifySignature: aSignature ofMessageHash: hash "Answer true if the given signature is the authentic signature of the given message hash. That is, if the signature must have been computed using the private key set corresponding to the given public key." | r s w u1 u2 v0 v | r _ aSignature first. s _ aSignature last. ((r > 0) and: [r < q]) ifFalse: [^ false]. "reject" ((s > 0) and: [s < q]) ifFalse: [^ false]. "reject" w _ s inverseModulo: q. u1 _ (hash asInteger * w) \\ q. u2 _ (r * w) \\ q. v0 _ (g raisedTo: u1 modulo: p) * (y raisedTo: u2 modulo: p). v _ ( v0 \\ p) \\ q. ^ v = r! ! !DSAPublicKey class methodsFor: 'instance creation' stamp: 'rww 1/4/2003 00:16' prior: 41809152! fromAsnDer: stream "Answers an instance of me derived from anASN1Value" | collection algorithm dssSig p q g y | collection := ASN1Value fromAsnDer: stream. algorithm := collection first. dssSig := algorithm last. (dssSig size = 3) ifFalse: [self error: 'incorrect number of dss parameters']. p := dssSig at: 1. q := dssSig at: 2. g := dssSig at: 3. y := ASN1Value fromAsnDer: collection last bytes readStream. ^ DSAPublicKey p: p q: q g: g y: y. ! ! !DSAPublicKey class methodsFor: 'instance creation' stamp: 'len 8/15/2002 02:20' prior: 41809696! p: p0 q: q0 g: g0 y: y0 ^ self new p: p0 q: q0 g: g0 y: y0! ! !DSAPublicKey class methodsFor: 'examples' stamp: 'rww 1/2/2003 02:31' prior: 41809831! notesOnAsnEncoding "Smalltalk at: #ASN1Constants put: Dictionary new!! ASN1Constants at: #classApplication put: 64!! ASN1Constants at: #classContextSpecific put: 128!! ASN1Constants at: #classPrivate put: 192!! ASN1Constants at: #classUniversal put: 0!! ASN1Constants at: #idBitString put: 3!! ASN1Constants at: #idBoolean put: 1!! ASN1Constants at: #idIA5String put: 22!! ASN1Constants at: #idInteger put: 2!! ASN1Constants at: #idNull put: 5!! ASN1Constants at: #idObjectIdentifier put: 6!! ASN1Constants at: #idOctetString put: 4!! ASN1Constants at: #idPrintableString put: 19!! ASN1Constants at: #idSequence put: 16!! ASN1Constants at: #idSet put: 17!! ASN1Constants at: #idUTCTime put: 23!! ASN1Constants at: #maskClass put: 192!! ASN1Constants at: #maskConstructed put: 32!! ASN1Constants at: #maskTag put: 31!! ASN1Constants at: #tagHigh put: 31!! Transcript show: 'ASN1ObjectIdentifiers'; cr!! Smalltalk at: #ASN1ObjectIdentifiers put: Dictionary new!! ASN1ObjectIdentifiers at: #x1x2x840x10040x4x1 put: ('id-dsa')!! ASN1ObjectIdentifiers at: #x1x2x840x10040x4x3 put: ('id-dsa-with-sha1')!! ASN1ObjectIdentifiers at: #x1x2x840x113533x7x65x0 put: ('entrustVersion')!! ASN1ObjectIdentifiers at: #x1x2x840x113549x1x1x1 put: ('rsaEncryption')!! ASN1ObjectIdentifiers at: #x1x2x840x113549x1x1x2 put: ('md2WithRSAEncryption')!! ASN1ObjectIdentifiers at: #x1x2x840x113549x1x1x4 put: ('md5WithRSAEncryption')!! ASN1ObjectIdentifiers at: #x1x2x840x113549x1x1x5 put: ('sha-1WithRSAEncryption')!! ASN1ObjectIdentifiers at: #x1x2x840x113549x1x9x1 put: ('e-mailAddress')!! ASN1ObjectIdentifiers at: #x1x3x14x3x2x12 put: ('dsa')!! ASN1ObjectIdentifiers at: #x1x3x14x3x2x27 put: ('dsa With SHA1')!! ASN1ObjectIdentifiers at: #x2x16x840x1x113730x1x1 put: ('netscapeCertificateType')!! ASN1ObjectIdentifiers at: #x2x16x840x1x113730x1x12 put: ('SslServerName')!! ASN1ObjectIdentifiers at: #x2x16x840x1x113730x1x13 put: ('netscapeCertificateComment')!! ASN1ObjectIdentifiers at: #x2x16x840x1x113730x1x2 put: ('BaseURL')!! ASN1ObjectIdentifiers at: #x2x16x840x1x113730x1x3 put: ('RevocationURL')!! ASN1ObjectIdentifiers at: #x2x16x840x1x113730x1x4 put: ('CARevocationURL')!! ASN1ObjectIdentifiers at: #x2x16x840x1x113730x1x7 put: ('renewalURL')!! ASN1ObjectIdentifiers at: #x2x16x840x1x113730x1x8 put: ('netscapeCaPolicyURL')!! ASN1ObjectIdentifiers at: #x2x5x29x14 put: ('subjectKeyIdentifier')!! ASN1ObjectIdentifiers at: #x2x5x29x15 put: ('keyUsage')!! ASN1ObjectIdentifiers at: #x2x5x29x16 put: ('privateKeyUsagePeriod')!! ASN1ObjectIdentifiers at: #x2x5x29x17 put: ('subjectAlternativeName')!! ASN1ObjectIdentifiers at: #x2x5x29x18 put: ('issuerAlternativeName')!! ASN1ObjectIdentifiers at: #x2x5x29x19 put: ('basicConstraints')!! ASN1ObjectIdentifiers at: #x2x5x29x20 put: ('cRLNumber')!! ASN1ObjectIdentifiers at: #x2x5x29x21 put: ('reasonCode')!! ASN1ObjectIdentifiers at: #x2x5x29x23 put: ('holdInstructionCode')!! ASN1ObjectIdentifiers at: #x2x5x29x24 put: ('invalidityDate')!! ASN1ObjectIdentifiers at: #x2x5x29x27 put: ('deltaCRLIndicator')!! ASN1ObjectIdentifiers at: #x2x5x29x28 put: ('issuingDistributionPoint')!! ASN1ObjectIdentifiers at: #x2x5x29x29 put: ('certificateIssuer')!! ASN1ObjectIdentifiers at: #x2x5x29x3 put: ('certificate policies - old')!! ASN1ObjectIdentifiers at: #x2x5x29x30 put: ('nameConstraints')!! ASN1ObjectIdentifiers at: #x2x5x29x31 put: ('cRLDistributionPoints')!! ASN1ObjectIdentifiers at: #x2x5x29x32 put: ('certificatePolicies')!! ASN1ObjectIdentifiers at: #x2x5x29x33 put: ('policyMappings')!! ASN1ObjectIdentifiers at: #x2x5x29x35 put: ('authorityKeyIdentifier')!! ASN1ObjectIdentifiers at: #x2x5x29x36 put: ('policyConstraints')!! ASN1ObjectIdentifiers at: #x2x5x4x10 put: ('O')!! ASN1ObjectIdentifiers at: #x2x5x4x11 put: ('OU')!! ASN1ObjectIdentifiers at: #x2x5x4x13 put: ('??')!! ASN1ObjectIdentifiers at: #x2x5x4x3 put: ('CN')!! ASN1ObjectIdentifiers at: #x2x5x4x6 put: ('C')!! ASN1ObjectIdentifiers at: #x2x5x4x7 put: ('L')!! ASN1ObjectIdentifiers at: #x2x5x4x8 put: ('S')!! ASN1ObjectIdentifiers at: #x2x5x8x1x1 put: ('rsa')!! "! ! !DSAPublicKey class methodsFor: 'examples' stamp: 'rww 1/2/2003 02:36' prior: 41814044! test1 | x509 key hash | x509 := #(48 130 1 184 48 130 1 44 6 7 42 134 72 206 56 4 1 48 130 1 31 2 129 129 0 253 127 83 129 29 117 18 41 82 223 74 156 46 236 228 231 246 17 183 82 60 239 68 0 195 30 63 128 182 81 38 105 69 93 64 34 81 251 89 61 141 88 250 191 197 245 186 48 246 203 155 85 108 215 129 59 128 29 52 111 242 102 96 183 107 153 80 165 164 159 159 232 4 123 16 34 194 79 187 169 215 254 183 198 27 248 59 87 231 198 168 166 21 15 4 251 131 246 211 197 30 195 2 53 84 19 90 22 145 50 246 117 243 174 43 97 215 42 239 242 34 3 25 157 209 72 1 199 2 21 0 151 96 80 143 21 35 11 204 178 146 185 130 162 235 132 11 240 88 28 245 2 129 129 0 247 225 160 133 214 155 61 222 203 188 171 92 54 184 87 185 121 148 175 187 250 58 234 130 249 87 76 11 61 7 130 103 81 89 87 142 186 212 89 79 230 113 7 16 129 128 180 73 22 113 35 232 76 40 22 19 183 207 9 50 140 200 166 225 60 22 122 139 84 124 141 40 224 163 174 30 43 179 166 117 145 110 163 127 11 250 33 53 98 241 251 98 122 1 36 59 204 164 241 190 168 81 144 137 168 131 223 225 90 229 159 6 146 139 102 94 128 123 85 37 100 1 76 59 254 207 73 42 3 129 133 0 2 129 129 0 209 171 224 141 87 74 186 36 200 200 42 40 228 114 112 206 104 250 213 194 178 215 57 23 135 248 223 239 188 97 167 102 105 90 234 151 109 222 24 29 72 142 144 0 11 95 96 125 132 94 155 201 238 92 229 249 108 218 81 237 57 70 21 226 217 118 235 29 215 214 73 236 204 148 72 7 26 167 85 90 96 4 15 232 157 127 208 172 107 241 4 180 137 245 183 54 97 233 185 114 47 14 37 221 10 6 183 240 46 247 196 150 223 119 107 80 145 214 222 138 248 230 247 102 1 229 209 193). key := DSAPublicKey fromAsnDer: x509 readStream. (key encodeAsnDer = x509) ifFalse: [self error: 'encodings different']. hash := SHA1 hashMessage: key encodeAsnDer. ^ (Base64MimeConverter mimeEncode: hash readStream) contents ! ! !DiffieHellman methodsFor: 'initialization' stamp: 'len 10/26/2002 16:04' prior: 41815950! generator: anInteger generator _ anInteger! ! !DiffieHellman methodsFor: 'initialization' stamp: 'len 10/26/2002 16:04' prior: 41816072! prime: anInteger prime _ anInteger! ! !DiffieHellman methodsFor: 'initialization' stamp: 'len 10/25/2002 13:45' prior: 41816186! setupPrimeOfSize: bits prime _ PrimesFinder safePrimeOfSize: bits. generator _ ElGamalKeyGenerator generatorOfZp: prime! ! !DiffieHellman methodsFor: 'accessing' stamp: 'len 10/26/2002 16:04' prior: 41816381! generator ^ generator! ! !DiffieHellman methodsFor: 'accessing' stamp: 'len 10/26/2002 16:03' prior: 41816477! prime ^ prime! ! !DiffieHellman methodsFor: 'protocol' stamp: 'cs 8/21/2002 12:20' prior: 41816562! receiveMessage: anInteger sharedKey _ anInteger raisedTo: secret modulo: prime. ^ sharedKey! ! !DiffieHellman methodsFor: 'protocol' stamp: 'cs 8/21/2002 12:20' prior: 41816726! sendMessage secret _ (1 to: prime-2) atRandom. ^ generator raisedTo: secret modulo: prime! ! !DiffieHellman methodsFor: 'protocol' stamp: 'len 8/27/2002 23:52' prior: 41816889! sharedKey ^ sharedKey! ! !DiffieHellman class methodsFor: 'instance creation' stamp: 'len 10/26/2002 16:06' prior: 41816999! bits: anInteger | prime generator | prime _ PrimesFinder safePrimeOfSize: anInteger. generator _ ElGamalKeyGenerator generatorOfZp: prime. ^ self prime: prime generator: generator! ! !DiffieHellman class methodsFor: 'instance creation' stamp: 'len 10/26/2002 16:06' prior: 41817270! prime: prime generator: generator ^ self new prime: prime; generator: generator! ! !ElGamalKeyGenerator methodsFor: 'accessing' stamp: 'cs 8/5/2002 20:02' prior: 41817427! privateKey ^ ElGamalPrivateKey setModulo: p generator: alpha secretExponent: a ! ! !ElGamalKeyGenerator methodsFor: 'accessing' stamp: 'cs 8/5/2002 20:00' prior: 41817592! publicKey ^ ElGamalPublicKey setModulo: p generator: alpha generatorRaisedToA: (alpha raisedTo: a modulo: p) ! ! !ElGamalKeyGenerator methodsFor: 'private' stamp: 'len 10/25/2002 13:45' prior: 41817789! generateKeysOfSize: numberOfBits p _ PrimesFinder safePrimeOfSize: numberOfBits. alpha _ self class generatorOfZp: p. a _ (1 to: p-2) atRandom! ! !ElGamalKeyGenerator class methodsFor: 'instance creation' stamp: 'len 8/27/2002 23:55' prior: 41818027! bits: anInteger ^ self new generateKeysOfSize: anInteger! ! !ElGamalKeyGenerator class methodsFor: 'utils' stamp: 'len 10/26/2002 16:30' prior: 41818166! generatorOfZp: safePrimeP "Finds a generator of Zp* where p is a safe prime: p = 2q+1 with q prime. The order of Zp* is n = p-1 = 2q, so we know the factorization of n. See Handbook of Applied Cryptography, Ch.4, p.163 " | alpha p n | p _ safePrimeP. n _ p - 1. [alpha _ (1 to: n) atRandom. ((alpha raisedTo: n/2 modulo: p) = 1 or: [(alpha raisedTo: 2 modulo: p) = 1])] whileFalse. ^ alpha! ! !ElGamalPrivateKey methodsFor: 'accessing' stamp: 'cs 8/5/2002 20:26' prior: 41818640! hashFunction ^ SHA1 new! ! !ElGamalPrivateKey methodsFor: 'accessing' stamp: 'cs 8/5/2002 20:05' prior: 41818739! setModulo: p generator: alpha secretExponent: a modulo _ p. generator _ alpha. secretExponent _ a.! ! !ElGamalPrivateKey methodsFor: 'actions' stamp: 'len 10/26/2002 16:30' prior: 41818916! decryptElement: anArray | gamma delta aux | gamma _ anArray at: 1. delta _ anArray at: 2. aux _ gamma raisedTo: (modulo - 1 - secretExponent) modulo: modulo. ^ aux * delta \\ modulo! ! !ElGamalPrivateKey methodsFor: 'actions' stamp: 'cs 12/5/2002 15:35' prior: 41819176! signMessage: aByteArray | hm k kinv r s | hm _ (self hashFunction hashMessage: aByteArray) asInteger. [k _ (1 to: modulo - 2) atRandom. (k gcd: modulo-1) = 1] whileFalse. r _ generator raisedTo: k modulo: modulo. kinv _ k inverseModulo: (modulo-1). s _ kinv * (hm - (secretExponent*r)) \\ (modulo-1). ^ Array with: r with: s! ! !ElGamalPrivateKey class methodsFor: 'instance creation' stamp: 'cs 8/5/2002 20:04' prior: 41819599! setModulo: p generator: alpha secretExponent: a ^ self new setModulo: p generator: alpha secretExponent: a ! ! !ElGamalPublicKey methodsFor: 'accessing' stamp: 'cs 8/5/2002 20:27' prior: 41819782! hashFunction ^ SHA1 new! ! !ElGamalPublicKey methodsFor: 'accessing' stamp: 'cs 8/5/2002 20:01' prior: 41819880! setModulo: p generator: alpha generatorRaisedToA: y modulo _ p. generator _ alpha. generatorRaisedToA _ y.! ! !ElGamalPublicKey methodsFor: 'actions' stamp: 'len 10/26/2002 16:31' prior: 41820064! encryptElement: anInteger | k gamma delta | k _ (1 to: modulo-2) atRandom. gamma _ generator raisedTo: k modulo: modulo. delta _ anInteger * (generatorRaisedToA raisedTo: k modulo: modulo) \\ modulo. ^ Array with: gamma with: delta! ! !ElGamalPublicKey methodsFor: 'actions' stamp: 'len 10/26/2002 16:31' prior: 41820375! verifySignature: anArray onMessage: aByteArray | hm r s v1 v2 | hm _ (self hashFunction hashMessage: aByteArray) asInteger. r _ anArray at: 1. s _ anArray at: 2. (r between: 1 and: modulo-1) ifFalse: [^ false]. "signature rejected" v1 _ generatorRaisedToA raisedTo: r modulo: modulo. v1 _ v1 * (r raisedTo: s modulo: modulo) \\ modulo. v2 _ generator raisedTo: hm modulo: modulo. ^ v1 = v2 "signature accepted if v1=v2"! ! !ElGamalPublicKey class methodsFor: 'instance creation' stamp: 'cs 8/5/2002 20:01' prior: 41820893! setModulo: p generator: alpha generatorRaisedToA: y ^ self new setModulo: p generator: alpha generatorRaisedToA: y! ! !HMAC methodsFor: 'initialization' stamp: 'len 10/16/2002 16:42' prior: 41821078! setHash: aHash hash _ aHash. ipad _ ByteArray new: aHash blockSize withAll: 16r36. epad _ ByteArray new: aHash blockSize withAll: 16r5C! ! !HMAC methodsFor: 'accessing' stamp: 'len 10/16/2002 16:43' prior: 41821281! digestMessage: aByteArray ^ hash hashMessage: (key bitXor: epad), (hash hashMessage: (key bitXor: ipad), aByteArray)! ! !HMAC methodsFor: 'accessing' stamp: 'len 8/3/2002 02:06' prior: 41821461! digestSize ^ hash hashSize! ! !HMAC methodsFor: 'accessing' stamp: 'len 10/16/2002 16:47' prior: 41821553! key: aByteArray key _ aByteArray. key size > hash blockSize ifTrue: [key _ hash hashMessage: key]. key size < hash blockSize ifTrue: [key _ key, (ByteArray new: hash blockSize - key size)]! ! !HMAC methodsFor: 'printing' stamp: 'len 8/3/2002 02:08' prior: 41821806! printOn: aStream aStream nextPutAll: 'HMAC-'; print: hash! ! !HMAC class methodsFor: 'instance creation' stamp: 'len 8/15/2002 01:42' prior: 41821942! on: aHashFunction ^ self new setHash: aHashFunction! ! !HashFunction methodsFor: 'accessing' stamp: 'len 8/15/2002 01:43' prior: 41822066! blockSize ^ self class blockSize! ! !HashFunction methodsFor: 'accessing' stamp: 'len 8/7/2002 16:30' prior: 41822170! hashMessage: aStringOrByteArray "MD5 new hashMessage: 'foo'" ^ self hashStream: aStringOrByteArray asByteArray readStream! ! !HashFunction methodsFor: 'accessing' stamp: 'len 8/9/2002 13:17' prior: 41822364! hashSize ^ self class hashSize! ! !HashFunction methodsFor: 'accessing' stamp: 'len 8/2/2002 02:21' prior: 41822466! hashStream: aStream ^ self subclassResponsibility! ! !HashFunction methodsFor: 'converting' stamp: 'len 8/3/2002 02:42' prior: 41822588! hmac ^ HMAC on: self! ! !HashFunction class methodsFor: 'hashing' stamp: 'len 8/2/2002 02:20' prior: 41822684! hashMessage: aStringOrByteArray ^ self new hashMessage: aStringOrByteArray! ! !HashFunction class methodsFor: 'hashing' stamp: 'len 8/2/2002 02:20' prior: 41822834! hashStream: aPositionableStream ^ self new hashStream: aPositionableStream! ! !HashFunction class methodsFor: 'accessing' stamp: 'len 8/15/2002 01:43' prior: 41822987! blockSize ^ self subclassResponsibility! ! !HashFunction class methodsFor: 'accessing' stamp: 'len 8/9/2002 13:17' prior: 41823104! hashSize ^ self subclassResponsibility! ! !Integer methodsFor: 'mathematical functions' stamp: 'len 11/14/2002 11:51' prior: 41823224! inverseModulo: n "Answer the inverse of the receiver modulus n. That is, the integer y such that (self * y) \\ n is 1. Both self and n must be positive, and it is assumed that self < n and that n is integer." "Details: Use the extended Euclidean algorithm, Schneier, p. 247." | v u k u1 u2 u3 t1 t2 t3 tmp | ((self <= 0) or: [n <= 0]) ifTrue: [self error: 'number and modulo must be greater than zero']. self >= n ifTrue: [self error: 'number must be < modulo']. v _ self. u _ n. k _ 0. [self even and: [n even and: [u > 0]]] whileTrue: [ "eliminate common factors of two" k _ k + 1. u _ u bitShift: -1. v _ v bitShift: -1]. u1 _ 1. u2 _ 0. u3 _ u. t1 _ v. t2 _ u - 1. t3 _ v. [ [u3 even ifTrue: [ ((u1 odd) or: [u2 odd]) ifTrue: [ u1 _ u1 + v. u2 _ u2 + u]. u1 _ u1 bitShift: -1. u2 _ u2 bitShift: -1. u3 _ u3 bitShift: -1]. ((t3 even) or: [u3 < t3]) ifTrue: [ tmp _ u1. u1 _ t1. t1 _ tmp. tmp _ u2. u2 _ t2. t2 _ tmp. tmp _ u3. u3 _ t3. t3 _ tmp]. u3 even and: [u3 > 0]] whileTrue: ["loop while u3 is even"]. [((u1 < t1) or: [u2 < t2]) and: [u1 > 0]] whileTrue: [ u1 _ u1 + v. u2 _ u2 + u]. u1 _ u1 - t1. u2 _ u2 - t2. u3 _ u3 - t3. t3 > 0] whileTrue: ["loop while t3 > 0"]. [u1 >= v and: [u2 >= u]] whileTrue: [ u1 _ u1 - v. u2 _ u2 - u]. u1 _ u1 bitShift: k. u2 _ u2 bitShift: k. u3 _ u3 bitShift: k. u3 = 1 ifFalse: [self error: 'no inverse']. ^ u - u2! ! !Integer methodsFor: 'mathematical functions' stamp: 'cs 12/5/2002 15:47' prior: 41824763! raisedTo: y modulo: n "Answer the modular exponential. Code by Jesse Welton." | s t u | s _ 1. t _ self. u _ y. [u = 0] whileFalse: [ u odd ifTrue: [ s _ s * t. s >= n ifTrue: [s _ s \\\ n]]. t _ t * t. t >= n ifTrue: [t _ t \\\ n]. u _ u bitShift: -1]. ^ s normalize ! ! !Integer methodsFor: 'asn1 encoding' stamp: 'rww 12/7/2002 23:27' prior: 41825123! areAllBitsSet ^self digitLength ~= (self + 1) digitLength! ! !Integer methodsFor: 'asn1 encoding' stamp: 'rww 1/2/2003 00:30' prior: 41825252! asArray | stream | stream := WriteStream on: Array new. self digitLength to: 1 by: -1 do: [:digitIndex | stream nextPut: (self digitAt: digitIndex)]. ^ stream contents ! ! !Integer methodsFor: 'asn1 encoding' stamp: 'rww 1/2/2003 00:29' prior: 41825497! asByteArray | stream | stream := WriteStream on: ByteArray new. self digitLength to: 1 by: -1 do: [:digitIndex | stream nextPut: (self digitAt: digitIndex)]. ^ stream contents ! ! !Integer methodsFor: 'asn1 encoding' stamp: 'rww 1/1/2003 11:25' prior: 41825750! encodeAsnDer | aStream | aStream := WriteStream on: (ByteArray new). self encodeAsnDerOn: aStream. ^aStream contents! ! !Integer methodsFor: 'asn1 encoding' stamp: 'rww 1/1/2003 11:27' prior: 41825941! encodeAsnDerBodyOn: aStream self positive ifTrue: [^self encodeAsnDerPositiveOn: aStream] ifFalse: [^self encodeAsnDerNegativeOn: aStream]! ! !Integer methodsFor: 'asn1 encoding' stamp: 'rww 1/1/2003 11:26' prior: 41826155! encodeAsnDerLengthOn: aStream self <= 127 ifTrue: [aStream nextPut: self] ifFalse: [ aStream nextPut: ((self digitLength) bitOr: 16r80). self digitLength to: 1 by: -1 do: [:digitIndex | aStream nextPut: (self digitAt: digitIndex)]]! ! !Integer methodsFor: 'asn1 encoding' stamp: 'rww 1/1/2003 12:23' prior: 41826473! encodeAsnDerNegativeOn: aStream | twosComplement | twosComplement := self negated twosComplement. (twosComplement lastDigit noMask: 16r80) ifTrue: [ (twosComplement digitLength+1) encodeAsnDerLengthOn: aStream. aStream nextPut: 16rFF] ifFalse: [twosComplement digitLength encodeAsnDerLengthOn: aStream]. twosComplement digitLength to: 1 by: -1 do: [:digitIndex | aStream nextPut: (twosComplement digitAt: digitIndex)]. ^aStream! ! !Integer methodsFor: 'asn1 encoding' stamp: 'rww 1/1/2003 12:19' prior: 41826988! encodeAsnDerOn: aStream aStream nextPut: 2. "tag" self encodeAsnDerBodyOn: aStream. ^aStream! ! !Integer methodsFor: 'asn1 encoding' stamp: 'rww 1/1/2003 12:21' prior: 41827155! encodeAsnDerPositiveOn: aStream (self lastDigit allMask: 16r80) ifTrue: [ (self digitLength+1) encodeAsnDerLengthOn: aStream. aStream nextPut: 0] ifFalse: [self digitLength encodeAsnDerLengthOn: aStream]. self digitLength to: 1 by: -1 do: [:digitIndex | aStream nextPut: (self digitAt: digitIndex)]. ^aStream! ! !Integer methodsFor: 'asn1 encoding' stamp: 'rww 1/13/2003 01:22' prior: 41827550! toEBase64String self < 0 ifTrue: [^ '-', self negated toEBase64String]. ^ self asByteArray toEBase64String. ! ! !Integer methodsFor: 'asn1 encoding' stamp: 'rww 12/7/2002 23:28' prior: 41827732! twosComplement | complement digit length | length := self digitLength + 1. complement := Integer new: length neg: false. 1 to: length-1 do: [:index | digit := self digitAt: index. digit := digit bitXor: 16rFF. "flip bits without 2's complement logic in bitInvert" complement digitAt: index put: digit]. self areAllBitsSet ifTrue: [complement digitAt: length put: 16rFF]. ^complement + 1! ! !Integer methodsFor: '*cryptography' stamp: 'rww 4/11/2004 14:47' prior: 41828202! asByteArrayOfSize: size "((( | repeats number | repeats := 1000000. number := 123456789123456789123456789123456789123456789123456789. [repeats timesRepeat: (number asByteArrayOfSize: 1024) ] timeToRun. )))" | bytes | size < self digitLength ifTrue: [^ self error: 'number too big for ', size asString]. bytes := self asByteArray. ^ (ByteArray new: (size - bytes size)), bytes ! ! !Integer class methodsFor: 'asn1 decoding' stamp: 'rww 1/2/2003 01:08' prior: 41828674! asnDerLengthFrom: aStream | byte length | byte := aStream next. byte <= 16r80 ifTrue: [^byte] ifFalse: [ length := 0. (byte bitAnd: 16r7F) timesRepeat: [ length := (length bitShift: 8) bitOr: aStream next]. ^ length].! ! !Integer class methodsFor: 'asn1 decoding' stamp: 'rww 1/2/2003 01:06' prior: 41828988! fromAsnDer: aStream | length integer | aStream skip: 1. "tag" length := self asnDerLengthFrom: aStream. length isNil ifTrue: [^nil]. integer := self new: length neg: false . length to: 1 by: -1 do: [:index | aStream atEnd ifTrue: [^nil] ifFalse: [integer digitAt: index put: aStream next]]. ((integer digitAt: length) allMask: 16r80) ifTrue: [^integer twosComplement negated normalize] ifFalse: [^integer normalize]! ! !MD4 methodsFor: 'initialization' stamp: 'len 10/16/2002 16:23' prior: 41829492! initialize a _ 16r67452301. b _ 16rEFCDAB89. c _ 16r98BADCFE. d _ 16r10325476. output _ ByteArray new: 16! ! !MD4 methodsFor: 'accessing' stamp: 'len 10/16/2002 16:28' prior: 41829666! hashMessage: aStringOrByteArray self input: aStringOrByteArray asByteArray. self run. ^ self output! ! !MD4 methodsFor: 'accessing' stamp: 'len 10/16/2002 16:28' prior: 41829832! hashStream: aStream ^ self hashMessage: aStream upToEnd! ! !MD4 methodsFor: 'accessing' stamp: 'LC 6/24/2001 15:46' prior: 41829950! input: anArray input _ anArray! ! !MD4 methodsFor: 'accessing' stamp: 'LC 6/24/2001 15:46' prior: 41830044! output ^ output! ! !MD4 methodsFor: 'functions' stamp: 'LC 10/26/2001 19:23' prior: 41830123! fFunction: x ^ ((b bitAnd: c) bitOr: (b bitInvert bitAnd: d)) + x! ! !MD4 methodsFor: 'functions' stamp: 'LC 6/24/2001 15:52' prior: 41830259! fRound: x shift: s a _ self lshift: a + (self fFunction: x) bits: s! ! !MD4 methodsFor: 'functions' stamp: 'LC 6/24/2001 15:47' prior: 41830390! gFunction: x ^ ((b bitAnd: c) bitOr: ((b bitAnd: d) bitOr: (c bitAnd: d))) + x + 16r5A827999! ! !MD4 methodsFor: 'functions' stamp: 'LC 6/24/2001 15:47' prior: 41830558! gRound: x shift: s a _ self lshift: a + (self gFunction: x) bits: s! ! !MD4 methodsFor: 'functions' stamp: 'LC 6/24/2001 15:47' prior: 41830690! hFunction: x ^ ((b bitXor: c) bitXor: d) + x + 16r6ED9EBA1! ! !MD4 methodsFor: 'functions' stamp: 'LC 6/24/2001 15:47' prior: 41830819! hRound: x shift: s a _ self lshift: a + (self hFunction: x) bits: s! ! !MD4 methodsFor: 'functions' stamp: 'LC 6/24/2001 15:47' prior: 41830951! lshift: u bits: s " (Md4 new lshift: 1 s: 33) printStringRadix: 2 " | lo | lo _ u bitAnd: 16rFFFFFFFF. ^ (lo << s bitAnd: 16rFFFFFFFF) bitOr: lo >> (32 - s)! ! !MD4 methodsFor: 'functions' stamp: 'LC 6/24/2001 15:48' prior: 41831188! turn | temp | temp _ d. d _ c. c _ b. b _ a. a _ temp! ! !MD4 methodsFor: 'copying' stamp: 'LC 6/24/2001 15:51' prior: 41831307! copy4: u to: anArray startingAt: n anArray at: n put: (u bitAnd: 16rFF); at: n + 1 put: (u >> 8 bitAnd: 16rFF); at: n + 2 put: (u >> 16 bitAnd: 16rFF); at: n + 3 put: (u >> 24 bitAnd: 16rFF)! ! !MD4 methodsFor: 'copying' stamp: 'LC 6/24/2001 15:51' prior: 41831571! copy4ToOutput self copy4: a to: output startingAt: 1; copy4: b to: output startingAt: 5; copy4: c to: output startingAt: 9; copy4: d to: output startingAt: 13! ! !MD4 methodsFor: 'copying' stamp: 'LC 6/24/2001 15:48' prior: 41831803! copy64: anArray ^ self copy64: anArray startingAt: 1! ! !MD4 methodsFor: 'copying' stamp: 'LC 10/26/2001 19:23' prior: 41831919! copy64: anArray startingAt: n | array u answer | array _ anArray collect: [:char | char asInteger]. answer _ Array new: 16. 1 to: answer size do: [:i | u _ (array at: i - 1 * 4 + 3 + n) << 24. u _ u bitOr: (array at: i - 1 * 4 + 2 + n) << 16. u _ u bitOr: (array at: i - 1 * 4 + 1 + n) << 8. u _ u bitOr: (array at: i - 1 * 4 + 0 + n) << 0. answer at: i put: u]. ^ answer! ! !MD4 methodsFor: 'computing' stamp: 'LC 6/24/2001 15:49' prior: 41832392! mdFour64: array | aa bb cc dd indexes s | aa _ a. bb _ b. cc _ c. dd _ d. indexes _ #(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16) readStream. s _ #(3 7 11 19 3 7 11 19 3 7 11 19 3 7 11 19) readStream. [indexes atEnd] whileFalse: [self fRound: (array at: indexes next) shift: s next; turn]. indexes _ #(1 5 9 13 2 6 10 14 3 7 11 15 4 8 12 16) readStream. s _ #(3 5 9 13 3 5 9 13 3 5 9 13 3 5 9 13) readStream. [indexes atEnd] whileFalse: [self gRound: (array at: indexes next) shift: s next; turn]. indexes _ #(1 9 5 13 3 11 7 15 2 10 6 14 4 12 8 16) readStream. s _ #(3 9 11 15 3 9 11 15 3 9 11 15 3 9 11 15) readStream. [indexes atEnd] whileFalse: [self hRound: (array at: indexes next) shift: s next; turn]. a _ a + aa bitAnd: 16rFFFFFFFF. b _ b + bb bitAnd: 16rFFFFFFFF. c _ c + cc bitAnd: 16rFFFFFFFF. d _ d + dd bitAnd: 16rFFFFFFFF! ! !MD4 methodsFor: 'computing' stamp: 'len 10/16/2002 16:26' prior: 41833349! run | n buffer bb j offset | buffer _ ByteArray new: 128. n _ input size. bb _ n * 8. j _ 0. [n > 64] whileTrue: [self mdFour64: (self copy64: input startingAt: j + 1). j _ j + 64. n _ n - 64]. buffer atAllPut: 0. 1 to: n do: [:i | buffer at: i put: (input at: j + i)]. buffer at: n + 1 put: 16r80. offset _ n <= 55 ifTrue: [56] ifFalse: [120]. self copy4: bb to: buffer startingAt: offset + 1. self mdFour64: (self copy64: buffer). n > 55 ifTrue: [self mdFour64: (self copy64: buffer startingAt: 64)]. buffer atAllPut: 0. self copy4ToOutput. a _ b _ c _ d _ 0! ! !MD4 class methodsFor: 'instance creation' stamp: 'LC 10/26/2001 19:12' prior: 41834034! encode: aString ^ (self input: aString) run; output! ! !MD4 class methodsFor: 'instance creation' stamp: 'LC 6/24/2001 15:49' prior: 41834169! input: anArray ^ self new input: anArray! ! !MD4 class methodsFor: 'instance creation' stamp: 'LC 6/24/2001 15:49' prior: 41834288! new ^ super new initialize! ! !MD5 methodsFor: 'initialization' stamp: 'DSM 1/20/2000 17:56' prior: 41834384! initialize "Some magic numbers to get the process started" state _ OrderedCollection newFrom: { (ThirtyTwoBitRegister new load: 16r67452301). (ThirtyTwoBitRegister new load: 16rEFCDAB89). (ThirtyTwoBitRegister new load: 16r98BADCFE). (ThirtyTwoBitRegister new load: 16r10325476)}. ! ! !MD5 methodsFor: 'accessing' stamp: 'len 8/2/2002 03:17' prior: 41834738! hashStream: aPositionableStream "MD5 new hashStream: (ReadStream on: 'foo')" | startPosition buf bitLength | self initialize. "aPositionableStream atEnd ifTrue: [self error: 'empty stream']." startPosition _ aPositionableStream position. [aPositionableStream atEnd] whileFalse: [ buf _ aPositionableStream next: 64. (aPositionableStream atEnd not and: [buf size = 64]) ifTrue: [self processBuffer: buf] ifFalse: [ bitLength _ (aPositionableStream position - startPosition) * 8. self processFinalBuffer: buf bitLength: bitLength]]. ^ self finalValue! ! !MD5 methodsFor: 'private-functions' stamp: 'DSM 1/20/2000 01:47' prior: 41835385! fX: x Y: y Z: z " compute 'xy or (not x)z'" ^ x copy bitAnd: y; bitOr: (x copy bitInvert; bitAnd: z) ! ! !MD5 methodsFor: 'private-functions' stamp: 'DSM 1/20/2000 13:38' prior: 41835561! ffA: a B: b C: c D: d M: m S: s T: t "compute a = b + ((a + f(b,c,d) + m + t) <<< s)" ^ a += (self fX: b Y: c Z: d); += m; += t; leftRotateBy: s; += b. ! ! !MD5 methodsFor: 'private-functions' stamp: 'DSM 1/20/2000 01:48' prior: 41835786! gX: x Y: y Z: z " compute 'xz or y(not z)'" ^ x copy bitAnd: z; bitOr: (z copy bitInvert; bitAnd: y) ! ! !MD5 methodsFor: 'private-functions' stamp: 'DSM 1/20/2000 13:38' prior: 41835962! ggA: a B: b C: c D: d M: m S: s T: t "compute a = b + ((a + g(b,c,d) + m + t) <<< s)" ^ a += (self gX: b Y: c Z: d); += m; += t; leftRotateBy: s; += b. ! ! !MD5 methodsFor: 'private-functions' stamp: 'DSM 1/20/2000 01:48' prior: 41836187! hX: x Y: y Z: z " compute 'x xor y xor z'" ^ x copy bitXor: y; bitXor: z ! ! !MD5 methodsFor: 'private-functions' stamp: 'DSM 1/20/2000 13:38' prior: 41836335! hhA: a B: b C: c D: d M: m S: s T: t "compute a = b + ((a + h(b,c,d) + m + t) <<< s)" ^ a += (self hX: b Y: c Z: d); += m; += t; leftRotateBy: s; += b. ! ! !MD5 methodsFor: 'private-functions' stamp: 'DSM 1/20/2000 01:48' prior: 41836560! iX: x Y: y Z: z " compute 'y xor (x or (not z))'" ^ y copy bitXor: (z copy bitInvert; bitOr: x) ! ! !MD5 methodsFor: 'private-functions' stamp: 'DSM 1/20/2000 13:39' prior: 41836729! iiA: a B: b C: c D: d M: m S: s T: t "compute a = b + ((a + i(b,c,d) + m + t) <<< s)" ^ a += (self iX: b Y: c Z: d); += m; += t; leftRotateBy: s; += b. ! ! !MD5 methodsFor: 'private-functions' stamp: 'DSM 1/20/2000 17:58' prior: 41836954! step: data template: item selector: selector "Perform one step in the round" | args | args _ { state at: (item at: 1). state at: (item at: 2). state at: (item at: 3). state at: (item at: 4). data at: (item at: 5). item at: 6. item at: 7 }. (self perform: selector withArguments: args). ! ! !MD5 methodsFor: 'private-buffers' stamp: 'len 10/15/2002 19:58' prior: 41837332! finalValue "Concatenate the state values to produce the 128-bite result" ^ (state at: 1) asByteArray, (state at: 2) asByteArray, (state at: 3) asByteArray, (state at: 4) asByteArray! ! !MD5 methodsFor: 'private-buffers' stamp: 'mdr 2/23/2001 22:50' prior: 41837584! processBuffer: aByteArray "Process a 64-byte buffer" | saveState data | saveState _ state collect: [ :item | item copy ]. data _ Array new: 16. 1 to: 16 do: [ :index | data at: index put: (ThirtyTwoBitRegister new reverseLoadFrom: aByteArray at: (index * 4) - 3)]. self rounds: data. 1 to: 4 do: [ :index | (state at: index) += (saveState at: index) ]. ! ! !MD5 methodsFor: 'private-buffers' stamp: 'DSM 1/20/2000 17:55' prior: 41838019! processFinalBuffer: aByteArray bitLength: bitLength "Pad the buffer until we have an even 64 bytes, then transform" | out | out _ ByteArray new: 64. out replaceFrom: 1 to: aByteArray size with: aByteArray startingAt: 1. aByteArray size < 56 ifTrue: [ out at: aByteArray size + 1 put: 128. "trailing bit" self storeLength: bitLength in: out. self processBuffer: out. ^ self]. "not enough room for the length, so just pad this one, then..." aByteArray size < 64 ifTrue: [ out at: aByteArray size + 1 put: 128 ]. self processBuffer: out. "process one additional block of padding ending with the length" out _ ByteArray new: 64. "filled with zeros" aByteArray size = 64 ifTrue: [ out at: 1 put: 128]. self storeLength: bitLength in: out. self processBuffer: out. ! ! !MD5 methodsFor: 'private-buffers' stamp: 'DSM 1/20/2000 17:19' prior: 41838872! storeLength: bitLength in: aByteArray "Fill in the final 8 bytes of the given ByteArray with a 64-bit little-endian representation of the original message length in bits." | n i | n _ bitLength. i _ aByteArray size - 8 + 1. [n > 0] whileTrue: [ aByteArray at: i put: (n bitAnd: 16rFF). n _ n bitShift: -8. i _ i + 1]. ! ! !MD5 methodsFor: 'private-rounds' stamp: 'DSM 1/20/2000 17:57' prior: 41839271! round: data selector: selector round: round "Do one round with the given function" | shiftIndex template abcd | 1 to: 16 do: [ :i | shiftIndex _ (i - 1) \\ 4 + 1. abcd _ ABCDTable at: shiftIndex. template _ { abcd at: 1. abcd at: 2. abcd at: 3. abcd at: 4. (IndexTable at: round) at: i. (ShiftTable at: round) at: shiftIndex. SinTable at: round - 1 * 16 + i }. self step: data template: template selector: selector ]. ! ! !MD5 methodsFor: 'private-rounds' stamp: 'DSM 1/20/2000 17:58' prior: 41839781! rounds: data "Perform the four rounds with different functions" #( ffA:B:C:D:M:S:T: ggA:B:C:D:M:S:T: hhA:B:C:D:M:S:T: iiA:B:C:D:M:S:T: ) doWithIndex: [ :selector :index | self round: data selector: selector round: index.] ! ! !MD5 class methodsFor: 'class initialization' stamp: 'mdr 2/23/2001 22:50' prior: 41840092! initialize "MD5 initialize" "Obscure fact: those magic hex numbers that are hard to type in correctly are actually the result of a simple trigonometric function and are therefore easier to compute than proofread. Laziness is sometimes a virtue." | c | c _ 2 raisedTo: 32. SinTable _ Array new: 64. 1 to: 64 do: [ :i | SinTable at: i put: (ThirtyTwoBitRegister new load: (c * i sin abs) truncated)]. ShiftTable _ { #(7 12 17 22). #(5 9 14 20). #(4 11 16 23). #(6 10 15 21) }. IndexTable _ { #(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16). #(2 7 12 1 6 11 16 5 10 15 4 9 14 3 8 13). #(6 9 12 15 2 5 8 11 14 1 4 7 10 13 16 3). #(1 8 15 6 13 4 11 2 9 16 7 14 5 12 3 10) }. ABCDTable _ { #(1 2 3 4). #(4 1 2 3). #(3 4 1 2). #(2 3 4 1) } ! ! !MD5 class methodsFor: 'accessing' stamp: 'len 8/15/2002 01:44' prior: 41840940! blockSize ^ 64! ! !MD5 class methodsFor: 'accessing' stamp: 'len 8/15/2002 01:44' prior: 41841024! hashSize ^ 16! ! !MillerRabin methodsFor: 'accessing' stamp: 'len 8/3/2002 21:30' prior: 41841108! error ^ 1 / (4 raisedTo: iterations)! ! !MillerRabin methodsFor: 'accessing' stamp: 'len 1/26/1999 19:42' prior: 41841217! iterations ^ iterations! ! !MillerRabin methodsFor: 'accessing' stamp: 'len 1/26/1999 19:43' prior: 41841313! satisfied ^ satisfied! ! !MillerRabin methodsFor: 'accessing' stamp: 'len 1/26/1999 19:44' prior: 41841407! target: anInteger target _ anInteger. self reset! ! !MillerRabin methodsFor: 'computing' stamp: 'len 8/3/2002 21:33' prior: 41841529! iterate | b t x | iterations _ iterations + 1. b _ samples atRandom. (target gcd: b) = 1 ifFalse: [^ satisfied _ false]. t _ 0. x _ b raisedTo: n0 modulo: target. (x = 1 or: [x = minusOne]) ifFalse: [ [x _ x squared \\ target. t _ t + 1. satisfied _ x = minusOne. satisfied not and: [t < k]] whileTrue. satisfied ifFalse: [^ satisfied]] ! ! !MillerRabin methodsFor: 'computing' stamp: 'LC 1/16/2002 08:22' prior: 41841953! reset iterations _ 0. satisfied _ true. minusOne _ target - 1. samples _ 1 to: minusOne. k _ minusOne lowBit - 1. n0 _ minusOne bitShift: k negated! ! !MillerRabin class methodsFor: 'primality testing' stamp: 'len 10/26/2002 16:25' prior: 41842198! isProbablyPrime: p | probabilistic | probabilistic _ self new. probabilistic target: p. [probabilistic satisfied and: ["error > (1 / 1024)" p