From VisualWorks®, 7.6 of February 1, 2008 on February 1, 2008 at 12:31:45 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>DSASignature</name> <environment>Security</environment> <super>Core.Object</super> <private>false</private> none r s <imports></imports> <category>Security-Ciphers</category> <attributes> <package>DSA</package> </attributes> </class> <comment> Security.DSASignature
This class represents a DSA signature which consists of two large integers. Instances are usually generated using the DSA signing operation. Instance Variables: r <LargePositiveInteger> signature parameter s <LargePositiveInteger> signature parameter
</comment> <class> <name>DSAKey</name> <environment>Security</environment> <super>Security.EncryptionKey</super> <private>false</private> none p q g <imports></imports> <category>Security-Ciphers</category> <attributes> <package>DSA</package> </attributes> </class> <comment> Security.DSAKey
Abstract superclass for DSA keys. Instance Variables: p <LargeInteger> a large prime of bit-length l, such that p=jq+1, where j >= 2 q <LargeInteger> a large prime of bit-length 160 g <LargeInteger> generator that has order q mod p
</comment> <class> <name>DSAPrivateKey</name> <environment>Security</environment> <super>Security.DSAKey</super> <private>false</private> none x <imports></imports> <category>Security-Ciphers</category> <attributes> <package>DSA</package> </attributes> </class> <comment> Security.DSAPrivateKey
Private DSA keys can be used to generate a signature for specific data which can later be verified using corresponding public key. For standardized export/import and secure storage of private keys use the PKCS8 package. Instance Variables: x <LargeInteger> randomly generated private parameter, 0 < x < q
</comment> <class> <name>DSAPublicKey</name> <environment>Security</environment> <super>Security.DSAKey</super> <private>false</private> none y <imports></imports> <category>Security-Ciphers</category> <attributes> <package>DSA</package> </attributes> </class> <comment> Security.DSAPublicKey
Public DSA key is used to verify a signature for specific data which was previously generated using corresponding private key. Instance Variables: y <LargeInteger> public parameter, y = g^x mod p
</comment> <class> <name>DSA</name> <environment>Security</environment> <super>Security.AsymmetricCipher</super> <private>false</private> none sha privateKey publicKey random random <imports></imports> <category>Security-Ciphers</category> <attributes> <package>DSA</package> </attributes> </class> <comment> Security.DSA
This class implements Digital Signature Algorithm (DSA) of the U.S. government's Digital Signature Standard (DSS). The DSA algorithm was proposed in 1991 and became a standard in May 1994. The official description is available as a Federal Information Processing Standards Publication (FIPS PUB 186, May 19, 1994; http://csrc.nist.gov/CryptoToolkit/tkdigsigs.html). A companion standard, the Secure Hash Standard, or SHS (FIPS PUB 180-1, April 17, 1995), describes a 160-bit message digest algorithm known as the Secure Hash Algorithm (SHA). This message digest is used to compute the signature. DSA does not support encryption, only signing. To sign some data an instance of the algorithm has to be initialized with a private key, and then the #sign: message can be used to generate the signature: aDSASignature := DSA new privateKey: aDSAPrivateKey; sign: byteData Signatures are verified with #verify:of: message sent to an algorithm instance initialized with the singer's public key: isAuthenticBoolean := DSA new publicKey: aDSAPublicKey; verify: aDSASignature of: byteData Instance Variables: sha <SHA> hash algorithm processing messages before signing privateKey <DSAPrivateKey> the key used for signing publicKey <DSAPublicKey> the key used for verifying signatures random <DSSRandom> random generator used in the signing process Class Instance Variables: random <Random> the default random generator
</comment> <class> <name>DSAKeyGenerator</name> <environment>Security</environment> <super>Security.KeyGenerator</super> <private>false</private> none sha q p g x y seed seedMask counter <imports></imports> <category>Security-Ciphers</category> <attributes> <package>DSA</package> </attributes> </class> <comment> Security.DSAKeyGenerator
DSA key generator is described in the DSS standard itself. The standard restricts the key size parameter (refered to as l) to multiples of 64 starting at 512 and ending with 1024. The key generator employs a random number generator and an efficient primality test. The random generator is expected to generate large intergers of 160 bit size, a properly seeded DSSRandom is acceptable. The primality test is allowed to be probabilistic but the probability of false prime has to be less than 1/4^50. A properly initialized MillerRabin algorithm is acceptable. The probabilistic primality test can share its random generator with the key generator. The generator produces a sequence of parameters, signalling various events along the way for observation. Finally it packages them up as DSAPublicKey and DSAPrivateKey, which are accessible using the #privateKey and #publicKey messages. To force the generator to produce a new pair of keys it has to be cleared using the #flush message. The generator also provides additional parameters #seed and #counter that can be used to verify quality of the public key by other parties. | generator public private | generator := DSAKeyGenerator keySize: 768. private := generator privateKey. public := generator publicKey. generator flush Instance Variables: sha <SHA> an instance of the hash function q <LargeInteger> a large prime of bit-length 160 p <LargeInteger> a large prime of bit-length l, such that p=jq+1, where j >= 2 g <LargeInteger> generator that has order q mod p x <LargeInteger> randomly generated private parameter, 0 < x < q y <LargeInteger> public parameter, y = g^x mod p seed <LargeInteger> the seed used to generate q seedMask <LargeInteger> the seed mask cache, (2 raisedTo: seed basicSize) - 1 counter <SmallInteger> the counter value that yielded p
</comment> <class> <name>DSAError</name> <environment>Security</environment> <super>Core.Error</super> <private>false</private> none <imports></imports> <category>Security-Ciphers</category> <attributes> <package>DSA</package> </attributes> </class> <comment> Security.DSAError
Represents errors raised by the DSA algorithm.
</comment> <methods> Security.DSASignature <category>accessing</category>
r ^r
s ^s
</methods> <methods> Security.DSASignature <category>intialization</category>
r: rLargePositiveInteger s: sLargePositiveInteger r := rLargePositiveInteger. s := sLargePositiveInteger
</methods> <methods> Security.DSASignature class <category>instance creation</category>
r: rLargePositiveInteger s: sLargePositiveInteger ^self new r: rLargePositiveInteger s: sLargePositiveInteger
</methods> <methods> Security.DSAKey <category>accessing</category>
g ^g
g: anInteger g := anInteger
p ^p
p: anInteger p := anInteger
q ^q
q: anInteger q := anInteger
</methods> <methods> Security.DSAPrivateKey <category>accessing</category>
x ^x
x: anInteger x := anInteger
</methods> <methods> Security.DSAPrivateKey class <category>instance creation</category>
p: p q: q g: g x: x | inst | inst := self new. inst p: p. inst q: q. inst g: g. inst x: x. ^inst
</methods> <methods> Security.DSAPublicKey <category>accessing</category>
y ^y
y: anInteger y := anInteger
</methods> <methods> Security.DSAPublicKey class <category>instance creation</category>
p: p q: q g: g y: y | inst | inst := self new. inst p: p. inst q: q. inst g: g. inst y: y. ^inst
</methods> <methods> Security.DSA <category>deprecated</category>
computeSignatureForMessageHash: hash privateKey: aPrivateKey "Answer the digital signature of the given message hash using the given private key. A signature is a pair of large integers. The private key is an array of four large integers: (p, q, g, x)." | p q g x r s k tmp | p := aPrivateKey p. q := aPrivateKey q. g := aPrivateKey g. x := aPrivateKey x. r := s := 0. [r = 0 or: [s = 0]] whileTrue: [ k := self nextRandom160 \\ q. r := (g raisedTo: k modulo: p) \\ q. tmp := (hash + (x * r)) \\ q. s := ((self inverseOf: k mod: q) * tmp) \\ q]. ^ DSASignature r: r s: s
verifySignature: aSignature ofMessageHash: hash publicKey: aPublicKey "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. The public key is an array of four large integers: (p, q, g, y)." | p q g y r s w u1 u2 v0 v | p := aPublicKey p. q := aPublicKey q. g := aPublicKey g. y := aPublicKey y. r := aSignature r. s := aSignature s. ((r > 0) and: [r < q]) ifFalse: [^ false]. "reject" ((s > 0) and: [s < q]) ifFalse: [^ false]. "reject" w := self inverseOf: s mod: q. u1 := (hash * w) \\ q. u2 := (r * w) \\ q. v0 := (g raisedTo: u1 modulo: p) * (y raisedTo: u2 modulo: p). v := ( v0 \\ p) \\ q. ^ v = r
</methods> <methods> Security.DSA <category>accessing</category>
privateKey ^privateKey
privateKey: aDSAPrivateKey privateKey := aDSAPrivateKey
publicKey ^publicKey
publicKey: aDSAPublicKey publicKey := aDSAPublicKey
random ^random ifNil: [random := self defaultRandom]
random: aDSSRandom random := aDSSRandom
</methods> <methods> Security.DSA <category>private</category>
defaultRandom ^self class random
inverseOf: x mod: n "Answer the inverse of x modulus n. That is, the integer y such that (x * y) \\ n is 1. Both x and n must be positive, and it is assumed that x < n and that x and n are integers." "Details: Use the extended Euclidean algorithm, Schneier, p. 247." " need to review to make faster" | v u k u1 u2 u3 t1 t2 t3 tmp | ((x <= 0) or: [n <= 0]) ifTrue: [self error: (#xnMustBePositive << #security >> 'x and n must be greater than zero')]. x >= n ifTrue: [self error: (#xMustBeLessThanN << #security >> 'x must be < n')]. v := x. u := n. k := 0. [x 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: (#NoInverse << #security >> 'no inverse')]. ^ u - u2
</methods> <methods> Security.DSA <category>initialization</category>
initialize sha := SHA new.
</methods> <methods> Security.DSA <category>services</category>
decrypt: aByteArray "Decrypt aByteArray using the previously assigned private key." "This algorithm doesn't support encryption" ^self shouldNotImplement
encrypt: aByteArray "Encrypts aByteArray using the previously assigned public key" "This algorithm doesn't support encryption" ^self shouldNotImplement
sign: aByteObject ^self signDigestInteger: (sha integerHash: aByteObject)
signDigest: aByteObject ^self signDigestInteger: ( aByteObject isInteger ifTrue: [aByteObject] ifFalse: [aByteObject asLargePositiveInteger])
signDigestInteger: aLargePositiveInteger | p q g x r s k tmp | privateKey ifNil: [ self error: (#NeedPrivateKeyToSign << #security >> 'Private key needed for signing!')]. p := privateKey p. q := privateKey q. g := privateKey g. x := privateKey x. r := s := 0. [r = 0 or: [s = 0]] whileTrue: [ k := self random next \\ q. r := (g raisedTo: k modulo: p) \\ q. tmp := (aLargePositiveInteger + (x * r)) \\ q. s := ((self inverseOf: k mod: q) * tmp) \\ q]. ^ DSASignature r: r s: s
verify: aSignature of: aByteObject ^self verify: aSignature ofDigestInteger: (sha integerHash: aByteObject)
verify: aSignature ofDigest: aByteObject ^self verify: aSignature ofDigestInteger: ( aByteObject isInteger ifTrue: [aByteObject] ifFalse: [aByteObject asLargePositiveInteger])
verify: aSignature ofDigestInteger: aLargePositiveInteger | p q g y r s w u1 u2 v0 v | publicKey ifNil: [ self error: (#NeedPublicKeyToVerify << #security >> 'Public key needed for signature verification!') ]. p := publicKey p. q := publicKey q. g := publicKey g. y := publicKey y. r := aSignature r. s := aSignature s. ((r > 0) and: [r < q]) ifFalse: [^ false]. "reject" ((s > 0) and: [s < q]) ifFalse: [^ false]. "reject" w := self inverseOf: s mod: q. u1 := (aLargePositiveInteger * w) \\ q. u2 := (r * w) \\ q. v0 := (g raisedTo: u1 modulo: p) * (y raisedTo: u2 modulo: p). v := ( v0 \\ p) \\ q. ^ v = r
</methods> <methods> Security.DSA class <category>deprecated</category>
sign: aStringOrStream privateKey: privateKey "Sign the given message (a stream or string) and answer a signature string." | dsa hasher h sig | dsa := DSA new. hasher := SHA new. (aStringOrStream isByteObject) ifTrue: [h := hasher integerHash: aStringOrStream] ifFalse: [h := hasher integerHashStream: aStringOrStream]. sig := dsa computeSignatureForMessageHash: h privateKey: privateKey. ^ self signatureToString: sig
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 r printStringRadix: 16. s nextPutAll: (hex copyFrom: 4 to: hex size). s space. hex := (aSignature s) printStringRadix: 16. s nextPutAll: (hex copyFrom: 4 to: hex size). s nextPutAll: ']'. ^ s contents
stringToSignature: aString "Answer the signature stored in the given string. A signature string has the format: '[DSA digital signature <r> <s>]' where <r> and <s> 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. ^ DSASignature r: r s: s
verify: signatureString isSignatureOf: aStringOrStream publicKey: publicKey "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." | dsa hasher h sig | dsa := DSA new. hasher := SHA new. (aStringOrStream isByteObject) ifTrue: [h := hasher integerHash: aStringOrStream] ifFalse: [h := hasher integerHashStream: aStringOrStream]. sig := self stringToSignature: signatureString. ^ dsa verifySignature: sig ofMessageHash: h publicKey: publicKey
verifySignature: aDSASignature isSignatureOf: aStringOrStream publicKey: publicKey "Answer true if the given DSASignature signs the given message (a stream or string)." | dsa hasher h | dsa := DSA new. hasher := SHA new. (aStringOrStream isByteObject) ifTrue: [h := hasher integerHash: aStringOrStream] ifFalse: [h := hasher integerHashStream: aStringOrStream]. ^ dsa verifySignature: aDSASignature ofMessageHash: h publicKey: publicKey
</methods> <methods> Security.DSA class <category>instance creation</category>
new ^super new initialize
</methods> <methods> Security.DSA class <category>accessing</category>
defaultRandom ^DSSRandom default
random ^random ifNil: [ self defaultRandom ]
random: aRandom "Set the default random generator for DSA algorithms. aRandom <Random> secure random generator " random := aRandom
</methods> <methods> Security.DSAKeyGenerator <category>accessing</category>
counter ^counter
g ^g
l ^keySize
p ^p
q ^q
seed ^seed
sha ^sha
x ^x
y ^y
</methods> <methods> Security.DSAKeyGenerator <category>initialization</category>
keySize: pLength random: aRandom primalityTest: pTest " pLength <SmallInteger> the bit-length of p, l = 512 + 64j, 0 <= j <= 8 aRandom <Random> a random seed generator producing large intergers of size 160 bits pTest <PrimalityTest> a probabilistic primality test, with error probability less than 1/4^50" super keySize: pLength random: aRandom primalityTest: pTest. sha := SHA new.
</methods> <methods> Security.DSAKeyGenerator <category>private</category>
generateG "Generates parameter G. Appendix 4, DSS" | j h | p ifNil: [ self generateP ]. j := (p - 1) / q. (j isInteger and: [j > 1]) ifFalse: [ DSAError new messageText: (#InvalidParameters << #security >> 'Invalid parameters !'); parameter: self; raise ]. h := 1. [h := h + 1. (g := h raisedTo: j modulo: p) = 1] whileTrue. self triggerEvent: #generatedG: with: g
generateP "Generates parameter P and a counter value." | n w b offset lMask q2 bMask | q ifNil: [ self generateQ ]. n := (keySize - 1) // 160. b := (keySize - 1) \\ 160. lMask := "2 raisedTo: l - 1" ((ByteArray new: keySize // 8 withAll: 0) at: keySize // 8 put: 128; yourself) changeClassTo: LargePositiveInteger. bMask := "(2 raisedTo: b) - 1" (ByteArray new: b // 8 withAll: 255) changeClassTo: LargePositiveInteger. q2 := q * 2. offset := 2. counter := 0. [ counter < 4096 ] whileTrue: [ w := (0 to: n) inject: 0 into: [ :total :k || v | v := sha hashInteger: (seed + offset + k bitAnd: seedMask). k = n ifTrue: [ v := v bitAnd: bMask ]. total + (v bitShift: 160 * k)]. w := w bitOr: lMask. p := w - (w \\ q2) + 1. self triggerEvent: #tryingP:counter: with: p with: counter. (p > lMask and: [ primalityTest value: p ]) ifTrue: [ self triggerEvent: #foundP:counter: with: p with: counter. ^self ]. counter := counter + 1. offset := offset + n + 1 ]. ^DSAError raiseSignal: (#ParameterGenerationFailed << #security >> 'Failed to generate parameters !')
generateQ "Generates parameter Q and a seed" | qMask | p := counter := nil. qMask := "(2 raisedTo: 159) + 1" ((ByteArray new: 20) at: 1 put: 1; at: 20 put: 128; yourself) changeClassTo: LargePositiveInteger. [ seed := random next. seedMask ifNil: [ seedMask := "(2 raisedTo: seed basicSize) - 1" (ByteArray new: seed basicSize withAll: 255) changeClassTo: LargePositiveInteger ]. q := ( (sha hashInteger: seed) bitXor: (sha hashInteger: (seed + 1 bitAnd: seedMask)) ) bitOr: qMask. self triggerEvent: #tryingQ:seed: with: q with: seed. primalityTest value: q ] whileFalse. self triggerEvent: #foundQ:seed: with: q with: seed
generateX "Generates private parameter X. Section 4, DSS" g ifNil: [ self generateG ]. [ (x := random next \\ q) > 0] whileFalse. self triggerEvent: #generatedX: with: x
generateY "Generates public parameter Y. Section 4, DSS" x ifNil: [ self generateX ]. y := g raisedTo: x modulo: p. self triggerEvent: #generatedY: with: y
</methods> <methods> Security.DSAKeyGenerator <category>services</category>
flush "Flush all the parameters to make sure next generation creates new ones" q := p := g := x := y := seed := seedMask := counter := nil
privateKey x ifNil: [ self generateX ]. ^DSAPrivateKey p: p q: q g: g x: x
publicKey y ifNil: [ self generateY ]. ^DSAPublicKey p: p q: q g: g y: y
</methods> <methods> Security.DSAKeyGenerator class <category>events</category>
eventsTriggered ^#( tryingQ:seed: foundQ:seed: tryingP:counter: foundP:counter: generatedG: generatedX: generatedY:)
</methods> <methods> Security.DSAKeyGenerator class <category>deprecated</category>
l: pLength ^self keySize: pLength
l: pLength random: aRandom ^self keySize: pLength random: aRandom
l: pLength random: aRandom primalityTest: pTest ^self keySize: pLength random: aRandom primalityTest: pTest
</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>EncryptionKey</name> <environment>Security</environment> <super>Core.Object</super> <private>false</private> none <imports></imports> <category>Security-Ciphers</category> <attributes> <package>CiphersBase</package> </attributes> </class> <class> <name>AsymmetricCipher</name> <environment>Security</environment> <super>Core.Object</super> <private>false</private> none <imports></imports> <category>Security-Ciphers</category> <attributes> <package>CiphersBase</package> </attributes> </class> <class> <name>KeyGenerator</name> <environment>Security</environment> <super>Core.EventManager</super> <private>false</private> none keySize random primalityTest random <imports></imports> <category>Security-Ciphers</category> <attributes> <package>CiphersBase</package> </attributes> </class> <class> <name>Error</name> <environment>Core</environment> <super>Core.Exception</super> <private>false</private> none <imports></imports> <category>Kernel-Exception Handling</category> <attributes> <package>Kernel-Exception Handling</package> </attributes> </class>