<?xml version="1.0"?>

<st-source>
<!-- 
Name: PKCS8
Notice: Copyright © 2008 Cincom Systems, Inc.  All Rights Reserved.
Comment: This package implements PKCS #8: Private-Key Information Syntax Standard (http://www.rsasecurity.com/rsalabs/node.asp?id=2130). This standard describes a binary encoding for transfer and storage of private-keys. Private-key information includes a private key for some public-key algorithm and a set of attributes.

The standard also describes encoding for encryption of private keys to protect their confidentiality. It proposes few specific methods of encryption based on password-based encryption algorithms from PKCS#5 (http://www.rsasecurity.com/rsalabs/node.asp?id=2127), see also package PKCS5. Given the highly sensitive nature of private keys, there's rarely a good reason to store or transport them unencrypted.

The standard doesn't cover the actual format for specific kinds of private keys and it's apparently non-trivial to find authoritative descriptions of those. The openssl man page for the pkcs8 command points in the direction of PKCS#11 (http://www.rsasecurity.com/rsalabs/node.asp?id=2133). That is what we have used as the source of these definititions as well. The relevant section from PKCS#11 v2.01 is section 11.9. The latest version, PKCS#11v2.20, covers it in section 12.6, which also adds few more formats for eliptic curve algorithms. This section is quoted in the PKCS8 class comment.


	LIMITATIONS

We support 2 types of keys
	- RSAPrivateKey
	- DSAPrivateKey

Encryption algorithm support is limited by the capabilities of our PKCS#5 implementation which currently means that we support the following:
	- DES for encryption and MD5 for key derivation (OID pbeWithMD5AndDES-CBC)
	- DES for encryption and SHA1 for key derivation (OID pbeWithSHA1AndDES- CBC)

These are amongst the most widely supported ones. Our plan is to add more secure versions based on RC4 and tripple DES (defined by PKCS#12, http://www.rsasecurity.com/rsalabs/node.asp?id=2138) in the near future. The default algorithm used for encryption is DES with SHA1.


	USAGE

The API is fairly straightforward. To encode a key on a stream use message #writeOn:, for example

	key := (RSAKeyGenerator bitSize: 512) privateKey.
	stream := ByteArray new readWriteStream.
	key writeOn: stream.

Note, that the stream must be binary and positionable. If you're writing the key out into a file, use an ExternalReadWriteStream, not just ExternalWriteStream which isn't positionable.
To read the key back from the stream use class side #readFrom: message.

	stream reset.
	RSAPrivateKey readFrom: stream.

There is an alternative API for reading keys on class side of PKCS8 class, so you can also read the key back as follows.

	stream reset.
	PKCS8 readKeyFrom: stream.

This is useful if you're not sure which type of key is next in the stream (DSA or RSA). The PKCS8 API will return whichever key type is there. The reading methods on the key classes (RSAPrivateKey or DSAPrivateKey) will raise a PKCS8Error if the key type on the stream doesn't match the key class, to prevent inadverent use of wrong key type. Therefore use PKCS8 class if you don't care what type of key you'll get, and use specific key class if you want specific key type.

The PKCS8 encoded keys are sometimes distributed in additional ASCII "armoring", called PEM format. This is basically the PKCS#8 bytes encoded in Base-64 encoding with some identification header and footer lines attached. For convenience we also provide equivalent reading methods for this PEM format #readPEMFrom: and #readKeyPEMFrom:. So you could read a key from a .pem file like this:

	PKCS8 readKeyPEMFrom: 'key.pem' asFilename readStream.


	ENCRYPTING KEYS

Private keys are highly sensitive information, therefore most of the time it is preferrable to keep the key encrypted while it is not used. The API to store a key encrypted is very much like the one shown earlier, it just acquires additional #password: keyword and parameter. The password parameter must be a ByteArray. We purposely choose not to provide a String based equivalent to avoid any ambiguities. It is up to the application to take care of the character encoding issues. Here's an example

	stream reset.
	password := 'very secret password' asByteArrayEncoding: #utf_16.
	key writeOn: stream password: password.

and to read the key back in

	stream reset.
	RSAPrivateKey readFrom: stream password: password.

or 

	stream reset.
	PKCS8 readKeyFrom: stream password: password.

The default algorithm used for key encryption is the PKCS#5, password-based encrytption using DES and SHA1 used to derive the encryption key from the provided password (identified by the PKCS#5 specification as pbeWithSHA1AndDES-CBC). It is possible to use other algorithms as well. See the documentation of the PKCS5 package for more details about these algorithms. Here we will discuss only how to choose and tune an algorithm for key encryption. Let's take the following example.

	stream reset.
	info := EncryptedPrivateKeyInfo PBE_MD5_DES.
	info algorithmIdentifier parameters count: 2048.
	info key: key password: password.
	info writeOn: stream.

We have to work directly with the EnryptedPrivateKeyInfo objects to tune encryption parameters. Choose the desired encryption algorithm by using the corresponding instance creation method, in this case PBE_MD5_DES (as opposed to the default which uses SHA1 instead of MD5). With the info instance in hand we can tweak specific parameters of the chosen algorithm. In this example we're explicitly increasing the "iteration count" to 2048. Again, details about these algorithms and their parameters belong to the PKCS#5 realm. Once the we have the algorithm set up the way we want we can store a key in the info instance using the #key:password: message. Note that the key is encrypted immediately, so any parameters must be tuned before this step. Finally we need to write the info instance out on the stream.

Reading this is much easier because all the information about the encryption altgorithm and specific parameters is stored along with the encrypted key. Therefore reading this is no different than reading a key encrypted with the default setup.

	stream reset.
	PKCS8 readKeyFrom: stream password: password.

DbIdentifier: bear73
DbTrace: 81615
DevelopmentPrerequisites: #(#(#any 'ASN1' '') #(#package 'SecurityBase' '') #(#package 'DSA' '') #(#package 'RSA' '') #(#package 'PKCS5' ''))
PackageName: PKCS8
Parcel: #('PKCS8')
PrerequisiteParcels: #(#('SecurityBase' '') #('ASN1' '') #('DSA' '') #('RSA' '') #('PKCS5' ''))
PrintStringCache: (751 0,mkobetic)
Version: 7.6
Date: 12:31:52 pm February 1, 2008
 -->
<time-stamp>From VisualWorks®, 7.6 of February 1, 2008 on February 1, 2008 at 12:31:52 pm</time-stamp>


<do-it>(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.']</do-it>

<class>
<name>PKCS8</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars>module types </class-inst-vars>
<imports>
			ASN1.*
			</imports>
<category>PKCS8</category>
<attributes>
<package>PKCS8</package>
</attributes>
</class>

<comment>
<class-id>Security.PKCS8</class-id>
<body>This class represents the ASN.1 application for PKCS #8. It maintains the ASN.1 module and provides protocols to (re)initialize the module, register all its ASN.1 types and SMI nodes of relevant OIDs, etc. It also holds APIs that don't belong on any of the more specific classes, for example APIs that can be used to decode/decrypt arbitrary key types (not known upfront) from a stream. 

As an FYI, here's a quote of the relevant section from PKCS #11 v2.01 section 11.9, which describes specific private key formats in use with PKCS#8. The latest version, PKCS#11 v2.20, has it in section 12.6, which also adds few more formats for eliptic curve algorithms:

---- PKCS #11 ----

11.9. Wrapping/unwrapping private keys (RSA, Diffie-Hellman, and DSA)

Cryptoki Version 2.01 allows the use of secret keys for wrapping and unwrapping RSA private keys, Diffie-Hellman private keys, and DSA private keys. For wrapping, a private key is BERencoded according to PKCS #8 s PrivateKeyInfo ASN.1 type. PKCS #8 requires an algorithm
identifier for the type of the secret key. The object identifiers for the required algorithm identifiers are as follows:

	rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 }
	dhKeyAgreement OBJECT IDENTIFIER ::= { pkcs-3 1 }
	id-dsa OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 1 }

where

	pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) US(840) rsadsi(113549) pkcs(1) 1 }
	pkcs-3 OBJECT IDENTIFIER ::= { iso(1) member-body(2) US(840) rsadsi(113549) pkcs(1) 3 }

These parameters for the algorithm identifiers have the following types, respectively:

    NULL

    DHParameter ::= SEQUENCE {
        prime INTEGER, -- p
        base INTEGER, -- g
        privateValueLength INTEGER OPTIONAL
    }

    Dss-Parms ::= SEQUENCE {
        p INTEGER,
        q INTEGER,
        g INTEGER
    }

Within the PrivateKeyInfo type:

* RSA private keys are BER-encoded according to PKCS #1 s RSAPrivateKey ASN.1 type. This type requires values to be present for all the attributes specific to Cryptoki s RSA private key objects. In other words, if a Cryptoki library does not have values for an RSA private key s CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT2, and CKA_COEFFICIENT values, it cannot create an RSAPrivateKey BER-encoding of the key, and so it cannot prepare it for wrapping.

* Diffie-Hellman private keys are represented as BER-encoded ASN.1 type INTEGER.

* DSA private keys are represented as BER-encoded ASN.1 type INTEGER.

Once a private key has been BER-encoded as a PrivateKeyInfo type, the resulting string of bytes is encrypted with the secret key. This encryption must be done in CBC mode with PKCS padding.

Unwrapping a wrapped private key undoes the above procedure. The CBC-encrypted ciphertext is decrypted, and the PKCS padding is removed. The data thereby obtained are parsed as a PrivateKeyInfo type, and the wrapped key is produced. An error will result if the original wrapped key does not decrypt properly, or if the decrypted unpadded data does not parse properly, or its type does not match the key type specified in the template for the new key. The unwrapping mechanism contributes only those attributes specified in the PrivateKeyInfo type to the newly-unwrapped key; other attributes must be specified in the template, or will take their default values.

Earlier drafts of PKCS #11 Version 2.0 and Version 2.01 used the object identifier

	DSA OBJECT IDENTIFIER ::= { algorithm 12 }
	algorithm OBJECT IDENTIFIER ::= { iso(1) identifier-organization(3) oiw(14) secsig(3) algorithm(2) }

with associated parameters

	DSAParameters ::= SEQUENCE {
		prime1 INTEGER, -- modulus p
		prime2 INTEGER, -- modulus q
		base INTEGER -- base g
	}

for wrapping DSA private keys. Note that although the two structures for holding DSA parameters appear identical when instances of them are encoded, the two corresponding object identifiers are different.

---- PKCS #11 ----

Class Instance Variables:
	module	&lt;ASN1.Module&gt; maintains the ASN.1 types for this application
	types	&lt;Set of: BindingReference&gt; records which classes contributed ASN.1 types to the module

</body>
</comment>

<class>
<name>AlgorithmIdentifier</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>oid parameters </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>PKCS8</category>
<attributes>
<package>PKCS8</package>
</attributes>
</class>

<comment>
<class-id>Security.AlgorithmIdentifier</class-id>
<body>RFC 3280 (section 4.1.1.2 signatureAlgorithm): The signatureAlgorithm field contains the identifier for the cryptographic algorithm used by the CA to sign this certificate. [RFC 3279] lists supported signature algorithms, but other signature algorithms MAY also be supported.

An algorithm identifier is defined by the following ASN.1 structure:

   AlgorithmIdentifier  ::=  SEQUENCE  {
        algorithm               OBJECT IDENTIFIER,
        parameters              ANY DEFINED BY algorithm OPTIONAL  }

The OBJECT IDENTIFIER component identifies the algorithm (such as DSA with SHA-1). The contents of the optional parameters field will vary according to the algorithm identified.

This field MUST contain the same algorithm identifier as the signature field in the sequence tbsCertificate (section 4.1.2.3).

Instance Variables:
	oid	&lt;Asn1OID&gt; 
	parameters	&lt;Object&gt; optional signing algorithm parameters

Shared Class Variables:
	AlgorithmFactories	&lt;Dictionary key: ObjectIdentifier value: BlockClosure&gt; maps OIDs to algorithm creating blocks
	KeyClasses	&lt;Dictionary key: ObjectIdentifier value: Class&gt; maps OIDs to private key classes
	OID_dsa	&lt;ObjectIdentifier&gt; oid for DSA algorithm
	OID_pbeWithMD5AndDES_CBC	&lt;ObjectIdentifier&gt; oid for PBE_MD5_DES encryption
	OID_pbeWithSHA1AndDES_CBC	&lt;ObjectIdentifier&gt; oid for PBE_SHA1_DES encryption
	OID_pbeWithSHAAnd128BitRC4	&lt;ObjectIdentifier&gt; oid for PBE_SHA1_RC4 encryption
	OID_pbeWithSHAAnd3_KeyTripleDES_CBC	&lt;ObjectIdentifier&gt; oid for PBE_SHA1_3DES encryption
	OID_rsaEncryption	&lt;ObjectIdentifier&gt; oid for RSA algorithm

</body>
</comment>

<class>
<name>DSSParameters</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>true</private>
<indexed-type>none</indexed-type>
<inst-vars>p q g </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>PKCS8</category>
<attributes>
<package>PKCS8</package>
</attributes>
</class>

<comment>
<class-id>Security.DSSParameters</class-id>
<body>DSSParameters describes DSAPrivateKey parameters. These are used as the 'parameters' aspect of DSA AlgorithmIdentifier instances.

Instance Variables:
	p	&lt;LargeInteger&gt; a large prime of bit-length l, such that p=jq+1, where j &gt;= 2
	q	&lt;LargeInteger&gt; a large prime of bit-length 160
	g	&lt;LargeInteger&gt;	generator that has order q mod p</body>
</comment>

<class>
<name>PrivateKeyInfo</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>true</private>
<indexed-type>none</indexed-type>
<inst-vars>version privateKeyAlgorithm privateKey attributes </inst-vars>
<class-inst-vars></class-inst-vars>
<imports>
			ASN1.*
			</imports>
<category>PKCS8</category>
<attributes>
<package>PKCS8</package>
</attributes>
</class>

<comment>
<class-id>Security.PrivateKeyInfo</class-id>
<body>PrivateKeyInfo information includes a private key for some public-key algorithm and a set of attributes.

Instance Variables:
	version	&lt;Integer&gt; version is the syntax version number, for compatibility with future revisions of this standard. It shall be 0 for this version of the standard
	privateKeyAlgorithm	&lt;AlgorithmIdentifier&gt; privateKeyAlgorithm identifies the private-key algorithm. One example of a private-key algorithm is PKCS #1's rsaEncryption.
	privateKey	&lt;ByteArray&gt; privateKey is an octet string whose contents are the value of the private key. The interpretation of the contents is defined in the registration of the private-key algorithm. For an RSA private key, for example, the contents are a BER encoding of a value of type RSAPrivateKey.
	attributes	&lt;OrderedCollection&gt; attributes allow to attach additional information to the private key

</body>
</comment>

<class>
<name>PBEParameter</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>true</private>
<indexed-type>none</indexed-type>
<inst-vars>salt iterationCount </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>PKCS8</category>
<attributes>
<package>PKCS8</package>
</attributes>
</class>

<comment>
<class-id>Security.PBEParameter</class-id>
<body>PBEParameter is the AlgorithmIdentifier parameter type for PKCS#5 encryption schemes (only the older ones, PBES1, in fact). See PKCS#5v2, section A.3 PBES1 (http://www.faqs.org/rfcs/rfc2898.html).

Instance Variables:
	salt	&lt;ByteArray&gt; specifies the salt value, an eight-octet string
	iterationCount	&lt;Integer&gt; specifies the iteration count

</body>
</comment>

<class>
<name>EncryptedPrivateKeyInfo</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>true</private>
<indexed-type>none</indexed-type>
<inst-vars>encryptedData encryptionAlgorithm </inst-vars>
<class-inst-vars>defaultAlgorithmIdentifier </class-inst-vars>
<imports>
			ASN1.*
			</imports>
<category>PKCS8</category>
<attributes>
<package>PKCS8</package>
</attributes>
</class>

<comment>
<class-id>Security.EncryptedPrivateKeyInfo</class-id>
<body>EncryptedPrivateKeyInfo holds encrypted PrivateKeyInfo, thus allowing to store private key information encrypted. It also contains identification of the algorithm and any parameters used for the encryption. Generally only algorithms from the PKCS#5 family (i.e. password based cryptography) are used, which is reflected in the API by the 'password' argument.

Instance Variables:
	encryptedData	&lt;ByteArray&gt; is the result of encrypting the private-key information.
	encryptionAlgorithm	&lt;AlgorithmIdentifier&gt; identifies the algorithm under which the private-key information is encrypted.

Class Instance Variables:
	defaultAlgorithmIdentifier	&lt;BlockClosure&gt; the default encryption algorithm to use

</body>
</comment>

<class>
<name>PKCS8Error</name>
<environment>Security</environment>
<super>Core.Error</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>PKCS8</category>
<attributes>
<package>PKCS8</package>
</attributes>
</class>

<comment>
<class-id>Security.PKCS8Error</class-id>
<body>Generic PKCS8 Error class.

</body>
</comment>

<shared-variable>
<name>OID_pbeWithSHAAnd128BitRC4</name>
<environment>Security.AlgorithmIdentifier</environment>
<private>false</private>
<constant>true</constant>
<category>oids</category>
<initializer>#(1 2 840 113549 1 12 1 1)  asAsn1OID</initializer>
<attributes>
<package>PKCS8</package>
</attributes>
</shared-variable>

<shared-variable>
<name>OID_rsaEncryption</name>
<environment>Security.AlgorithmIdentifier</environment>
<private>false</private>
<constant>true</constant>
<category>oids</category>
<initializer>#(1 2 840 113549 1 1 1)  asAsn1OID</initializer>
<attributes>
<package>PKCS8</package>
</attributes>
</shared-variable>

<shared-variable>
<name>OID_pbeWithSHA1AndDES_CBC</name>
<environment>Security.AlgorithmIdentifier</environment>
<private>false</private>
<constant>true</constant>
<category>oids</category>
<initializer>#(1 2 840 113549 1 5 10)  asAsn1OID</initializer>
<attributes>
<package>PKCS8</package>
</attributes>
</shared-variable>

<shared-variable>
<name>OID_pbeWithSHAAnd3_KeyTripleDES_CBC</name>
<environment>Security.AlgorithmIdentifier</environment>
<private>false</private>
<constant>true</constant>
<category>oids</category>
<initializer>#(1 2 840 113549 1 12 1 3)  asAsn1OID</initializer>
<attributes>
<package>PKCS8</package>
</attributes>
</shared-variable>

<shared-variable>
<name>OID_pbeWithMD5AndDES_CBC</name>
<environment>Security.AlgorithmIdentifier</environment>
<private>false</private>
<constant>true</constant>
<category>oids</category>
<initializer>#(1 2 840 113549 1 5 3)  asAsn1OID</initializer>
<attributes>
<package>PKCS8</package>
</attributes>
</shared-variable>

<shared-variable>
<name>OID_dsa</name>
<environment>Security.AlgorithmIdentifier</environment>
<private>false</private>
<constant>true</constant>
<category>oids</category>
<initializer>#(1 2 840 10040 4 1) asAsn1OID</initializer>
<attributes>
<package>PKCS8</package>
</attributes>
</shared-variable>

<shared-variable>
<name>KeyClasses</name>
<environment>Security.AlgorithmIdentifier</environment>
<private>false</private>
<constant>false</constant>
<category>stuff</category>
<initializer>IdentityDictionary new</initializer>
<attributes>
<package>PKCS8</package>
</attributes>
</shared-variable>

<shared-variable>
<name>AlgorithmFactories</name>
<environment>Security.AlgorithmIdentifier</environment>
<private>false</private>
<constant>false</constant>
<category>stuff</category>
<initializer>IdentityDictionary new</initializer>
<attributes>
<package>PKCS8</package>
</attributes>
</shared-variable>

<methods>
<class-id>Security.PKCS8 class</class-id> <category>accessing</category>

<body package="PKCS8" selector="module">module

	^module ifNil: [ module := Module new: #PKCS8 ]</body>

<body package="PKCS8" selector="register:">register: aClass
	
	self types add: aClass fullyQualifiedReference.
	aClass registerAsn1TypesIn: self module.</body>

<body package="PKCS8" selector="types">types
	^types ifNil: [types := Set new]</body>
</methods>

<methods>
<class-id>Security.PKCS8 class</class-id> <category>initialize-release</category>

<body package="PKCS8" selector="initialize">initialize
"
	self initialize
"
	self registerSMINodes.
	self register</body>

<body package="PKCS8" selector="register">register

	"Here we register types for classes that won't have their PKCS#8 class initialize method"
	self	register: RSAPrivateKey;
		register: DSAPrivateKey</body>

<body package="PKCS8" selector="registerSMINodes">registerSMINodes
"
	self registerSMINodes
"
	ASN1.SMINode root

	" PKCS #5 [RFC 2898] defines syntax for the key derivation functions, the encryption schemes, the message authentication scheme, and supporting techniques.
	The intended 	application of these definitions includes PKCS #8 and other syntax for key management, encrypted data, and integrity-protected data.
		rsadsi OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) 113549}
		pkcs OBJECT IDENTIFIER   ::= {rsadsi 1}
		pkcs-5 OBJECT IDENTIFIER ::= {pkcs 5}
		pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1}
		pbeWithMD2AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 4}
		pbeWithMD5AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 3}
		pbeWithMD5AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 6}
		pbeWithSHA1AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 10}
		pbeWithSHA1AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 11}
	"
		atPath: #( 1 2 840 113549 ) setSymbol: 'rsadsi';
		atPath: #( 1 2 840 113549 1 ) setSymbol: 'pkcs';
		atPath: #( 1 2 840 113549 1 5 ) setSymbol: 'pkcs-5';
		atPath: #( 1 2 840 113549 1 5 3 ) setSymbol: 'pbeWithMD5AndDES-CBC';
		atPath: #( 1 2 840 113549 1 5 10 ) setSymbol: 'pbeWithSHA1AndDES-CBC';

	"PKCS #12v1, Section B.4 adds few more PBE IDs:
		pkcs-12PbeIds OBJECT IDENTIFIER ::= {pkcs-12 1}
		pbeWithSHAAnd128BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 1}
		pbeWithSHAAnd40BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 2}
		pbeWithSHAAnd3-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 3}
		pbeWithSHAAnd2-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 4}
		pbeWithSHAAnd128BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 5}
		pbewithSHAAnd40BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 6}
"
		atPath: #( 1 2 840 113549 1 12 ) setSymbol: 'pkcs-12';
		atPath: #( 1 2 840 113549 1 12 1) setSymbol: 'pkcs-12PbeIds';
		atPath: #( 1 2 840 113549 1 12 1 1) setSymbol: 'pbeWithSHAAnd128BitRC4';
		atPath: #( 1 2 840 113549 1 12 1 2) setSymbol: 'pbeWithSHAAnd40BitRC4';
		atPath: #( 1 2 840 113549 1 12 1 3) setSymbol: 'pbeWithSHAAnd3-KeyTripleDES-CBC';
		atPath: #( 1 2 840 113549 1 12 1 4) setSymbol: 'pbeWithSHAAnd2-KeyTripleDES-CBC';
		atPath: #( 1 2 840 113549 1 12 1 5) setSymbol: 'pbeWithSHAAnd128BitRC2-CBC';
		atPath: #( 1 2 840 113549 1 12 1 6) setSymbol: 'pbewithSHAAnd40BitRC2-CBC';

		yourself</body>

<body package="PKCS8" selector="reset">reset
"Reinitialize the entire PKCS8 application, as if it was loaded from scratch.
	self reset
"
	| references |
	references := self types.
	module := nil.
	types := nil.
	references do: [ :ref |
		ref ifDefinedDo: [ :class |
			self  register: class ] ].
	AlgorithmIdentifier reset</body>
</methods>

<methods>
<class-id>Security.PKCS8 class</class-id> <category>services</category>

<body package="PKCS8" selector="readKeyFrom:">readKeyFrom: stream
"Read an unencrypted key from the stream
	stream &lt;Stream&gt; a readable byte stream with PKCS#8 encoding of the key 
	^&lt;RSAPrivateKey | DSAPrivateKey&gt;
"
	^PrivateKeyInfo readKeyFrom: stream</body>

<body package="PKCS8" selector="readKeyFrom:password:">readKeyFrom: stream password: password
"Read an encrypted key from the stream using the provided password.
	stream &lt;Stream&gt; a readable byte stream with PKCS#8 encoding of the key
	password &lt;ByteArray&gt;
	^&lt;RSAPrivateKey | DSAPrivateKey&gt;
"
	^EncryptedPrivateKeyInfo readKeyFrom: stream password: password</body>

<body package="PKCS8" selector="readKeyPEMFrom:">readKeyPEMFrom: stream
"Read an unencrypted key from the stream
	stream &lt;Stream&gt; a readable character stream with PEM armored PKCS#8 encoding of the key
	^&lt;RSAPrivateKey | DSAPrivateKey&gt;
"
	^PrivateKeyInfo readKeyPEMFrom: stream</body>

<body package="PKCS8" selector="readKeyPEMFrom:password:">readKeyPEMFrom: stream password: password
"Read an encrypted key from the stream using the provided password.
	stream &lt;Stream&gt; a readable character stream with PEM armored PKCS#8 encoding of the key
	password &lt;ByteArray&gt;
	^&lt;RSAPrivateKey | DSAPrivateKey&gt;
"
	^EncryptedPrivateKeyInfo readKeyPEMFrom: stream password: password</body>
</methods>

<methods>
<class-id>Security.PKCS8 class</class-id> <category>private-services</category>

<body package="PKCS8" selector="decodeBase64:">decodeBase64: aStream
	| stream output char |
	stream := EncodedStream on: aStream encodedBy: Protocols.Base64StreamEncoder asEncoder.
	output := (ByteArray new: 64) writeStream.
	[ (char := stream next) notNil ] whileTrue: [ output nextPut: char ].
	^output contents readStream</body>

<body package="PKCS8" selector="getPrivateKeyDataFrom:">getPrivateKeyDataFrom: aPEMStream
"Answers the Base64 encoded Private Key if 	aPEMStream has the appropriate delimiters required for PEM format; otherwise, answers nil"

	|  mark chunk |
	aPEMStream skipThroughAll: '-----BEGIN '.
	aPEMStream atEnd ifTrue: [^nil].
	mark := aPEMStream throughAll: '-----'.
	chunk := aPEMStream upToAll: '-----END ', mark.
	^(chunk copyWithout: Character cr) asByteArray</body>

<body package="PKCS8" selector="read:from:">read: typeName from: aStream

	^(DERStream wrap: aStream) unmarshalObjectType: (self module find: typeName)</body>

<body package="PKCS8" selector="readPEM:from:">readPEM: asn1Type from: aStream
" character stream"

	^(self getPrivateKeyDataFrom: aStream)
		ifNotNil: [ :b64 || bytes |
			bytes := self decodeBase64: b64 readStream.
			self read: asn1Type from: bytes ]</body>

<body package="PKCS8" selector="write:on:">write: anObject on: aStream 
	self 
		write: anObject 
		on: aStream 
		type: (self module find: anObject class asn1TypeName)</body>

<body package="PKCS8" selector="write:on:type:">write: anObject on: aStream type: asn1Type
	
	(DERStream wrap: aStream)
		marshalObject: anObject
		withType: asn1Type</body>
</methods>

<methods>
<class-id>Security.AlgorithmIdentifier</class-id> <category>marshaling</category>

<body package="PKCS8" selector="algorithm">algorithm

	^oid</body>

<body package="PKCS8" selector="algorithm:">algorithm: anOID

	oid := anOID</body>
</methods>

<methods>
<class-id>Security.AlgorithmIdentifier</class-id> <category>accessing-algorithms</category>

<body package="PKCS8" selector="encryptionAlgorithm">encryptionAlgorithm

	^(AlgorithmFactories
		at: self oid
		ifAbsent: [
			^PKCS8Error new
				messageText: (
					#PKCS8UnsupportedEncryptionAlgorithm1p &lt;&lt; #security &gt;&gt; 'Unsupported EncryptionAlgorithm &lt;1p&gt;'
						expandMacrosWith: self oid );
				parameter: self oid	
				raise ]
	) value: self</body>

<body package="PKCS8" selector="getAlgorithm">getAlgorithm

	| selector |
	selector := oid leafSymbol.
	(selector includes: $-) ifTrue: [
		selector := (selector asString replaceAll: $- with: $_) asSymbol ].
	^(self respondsTo: selector)
		ifTrue: [ self perform: selector ]
		ifFalse: [ nil ]</body>

<body package="PKCS8" selector="privateKeyClass">privateKeyClass

	^KeyClasses
		at: self oid
		ifAbsent: [
			PKCS8Error new
				messageText: (
					#PKCS8UnsupportedPrivateKeyType1p &lt;&lt; #security &gt;&gt; 'Unsupported Private Key Type &lt;1p&gt;'
						expandMacrosWith: self oid );
				parameter: self oid	
				raise ]</body>
</methods>

<methods>
<class-id>Security.AlgorithmIdentifier</class-id> <category>accessing</category>

<body package="PKCS8" selector="oid">oid

	^oid</body>

<body package="PKCS8" selector="oid:">oid: anObjectIdentifier

	^oid := anObjectIdentifier</body>

<body package="PKCS8" selector="parameters">parameters
	^parameters</body>

<body package="PKCS8" selector="parameters:">parameters: anObject

	parameters := anObject</body>
</methods>

<methods>
<class-id>Security.AlgorithmIdentifier</class-id> <category>testing</category>

<body package="PKCS8" selector="isDSA">isDSA
	^oid = OID_dsa</body>

<body package="PKCS8" selector="isRSA">isRSA
	^oid = OID_rsaEncryption</body>
</methods>

<methods>
<class-id>Security.AlgorithmIdentifier class</class-id> <category>accessing</category>

<body package="PKCS8" selector="asn1TypeName">asn1TypeName

	^#AlgorithmIdentifier</body>
</methods>

<methods>
<class-id>Security.AlgorithmIdentifier class</class-id> <category>instance creation</category>

<body package="PKCS8" selector="dsa">dsa
"Used to identify DSA private keys
	self dsa
"
	^self new
		algorithm: OID_dsa;
		yourself</body>

<body package="PKCS8" selector="pbeWithMD5AndDES_CBC">pbeWithMD5AndDES_CBC
"Used to identify corresponding PKCS#5 encryption algorithm for encrypted private keys.
	self pbeWithMD5AndDES_CBC
"
	^self new
		algorithm:  OID_pbeWithMD5AndDES_CBC;
		parameters: PBEParameter new
		yourself</body>

<body package="PKCS8" selector="pbeWithSHA1AndDES_CBC">pbeWithSHA1AndDES_CBC
"Used to identify corresponding PKCS#5 encryption algorithm for encrypted private keys.
 	self pbeWithSHA1AndDES_CBC
"
	^self new
		algorithm:  OID_pbeWithSHA1AndDES_CBC;
		parameters: PBEParameter new
		yourself</body>

<body package="PKCS8" selector="rsaEncryption">rsaEncryption
"Used to identify RSA private keys
	self rsaEncryption
"
	^self new
		algorithm: OID_rsaEncryption;
		"we need to force encoding of NULL value in the optional 'parameters' field"
		parameters: (nil withAsn1Type: ASN1.NULL new)
		yourself</body>
</methods>

<methods>
<class-id>Security.AlgorithmIdentifier class</class-id> <category>initialize-release</category>

<body package="PKCS8" selector="initialize">initialize
"
	self initialize
"
	self	initializeKeyClasses;
		initializeAlgorithmFactories;
		register</body>

<body package="PKCS8" selector="initializeAlgorithmFactories">initializeAlgorithmFactories
"
	#{AlgorithmFactories} binding reinitializeValue.
	self initializeAlgorithmFactories
"
	AlgorithmFactories
		at: OID_pbeWithMD5AndDES_CBC put: [ :identifier | PBC pbeWithMD5AndDES_CBC ];
		at: OID_pbeWithSHA1AndDES_CBC put: [ :identifier | PBC pbeWithSHA1AndDES_CBC ];
		"at: OID_pbeWithSHAAnd3_KeyTripleDES_CBC put: [ :identifier | PBC pbeWithSHAAnd3_KeyTripleDES_CBC ];"
		yourself</body>

<body package="PKCS8" selector="initializeKeyClasses">initializeKeyClasses
"
	#{KeyClasses} binding reinitializeValue.
	self initializeKeyClasses
"
	KeyClasses
		at: OID_dsa put: DSAPrivateKey;
		at: OID_rsaEncryption put: RSAPrivateKey;
		yourself</body>

<body package="PKCS8" selector="register">register
	PKCS8 register: self.</body>

<body package="PKCS8" selector="registerAsn1TypesIn:">registerAsn1TypesIn: module
"
	AlgorithmIdentifier  ::=  SEQUENCE  {
		algorithm               OBJECT IDENTIFIER,
		parameters              ANY DEFINED BY algorithm OPTIONAL  }
"
	( module SEQUENCE: self asn1TypeName )
		addElement: #algorithm type: #OBJECT_IDENTIFIER;
		addOptionalElement: #parameters type: (
			(ASN1.ANY definedBy: #algorithm)
				at: OID_pbeWithMD5AndDES_CBC put: ( module find: #PBEParameter );
				at: OID_pbeWithSHA1AndDES_CBC put: ( module find: #PBEParameter );
				at: OID_pbeWithSHAAnd3_KeyTripleDES_CBC put: ( module find: #PBEParameter );
				at: OID_pbeWithSHAAnd128BitRC4 put: ( module find: #PBEParameter );
				at: OID_dsa put: ( module find: #'Dss-Parms' );
				at: OID_rsaEncryption put: ASN1.NULL new;
				yourself);
		mapping: self</body>

<body package="PKCS8" selector="reset">reset
"
	self reset
"
	self asNameSpace bindingsDo: [ :binding | binding reinitializeValue ].
	self	initializeKeyClasses;
		initializeAlgorithmFactories</body>
</methods>

<methods>
<class-id>Security.AlgorithmIdentifier class</class-id> <category>instance creation - OpenSSL</category>

<body package="PKCS8" selector="PBE_MD5_DES">PBE_MD5_DES
"OpenSSL style alias.
	self PBE_MD5_DES
"
	^self pbeWithMD5AndDES_CBC</body>

<body package="PKCS8" selector="PBE_SHA1_DES">PBE_SHA1_DES
"OpenSSL style alias.
	self PBE_SHA1_DES
"
	^self pbeWithSHA1AndDES_CBC</body>
</methods>

<methods>
<class-id>Security.DSSParameters</class-id> <category>marshaling</category>

<body package="PKCS8" selector="g:">g: anObject
	g := anObject</body>

<body package="PKCS8" selector="p:">p: anObject
	p := anObject</body>

<body package="PKCS8" selector="q:">q: anObject
	q := anObject</body>
</methods>

<methods>
<class-id>Security.DSSParameters</class-id> <category>accessing</category>

<body package="PKCS8" selector="g">g
	^g</body>

<body package="PKCS8" selector="p">p
	^p</body>

<body package="PKCS8" selector="q">q
	^q</body>
</methods>

<methods>
<class-id>Security.DSSParameters class</class-id> <category>accessing</category>

<body package="PKCS8" selector="asn1TypeName">asn1TypeName

	^#'Dss-Parms'</body>
</methods>

<methods>
<class-id>Security.DSSParameters class</class-id> <category>initialize-release</category>

<body package="PKCS8" selector="initialize">initialize
	" self initialize "

	self register</body>

<body package="PKCS8" selector="register">register
	PKCS8 register: self.</body>

<body package="PKCS8" selector="registerAsn1TypesIn:">registerAsn1TypesIn: module
"        Dss-Parms  ::=  SEQUENCE  {
            p             INTEGER,
            q             INTEGER,
            g             INTEGER  }
"
	( module SEQUENCE: self asn1TypeName)
		addElement: #p type: #INTEGER;
		addElement: #q type: #INTEGER;
		addElement: #g type: #INTEGER;
		mapping: self</body>
</methods>

<methods>
<class-id>Security.PrivateKeyInfo</class-id> <category>accessing</category>

<body package="PKCS8" selector="algorithmIdentifier">algorithmIdentifier

	^self privateKeyAlgorithm</body>

<body package="PKCS8" selector="asByteArray">asByteArray
	| stream |
	stream := WriteStream on: (ByteArray new: 100).
	self writeOn: stream.
	^stream contents</body>

<body package="PKCS8" selector="attributes">attributes
	^attributes</body>

<body package="PKCS8" selector="attributes:">attributes: anOrderedCollection
	attributes := anOrderedCollection</body>

<body package="PKCS8" selector="key">key
"Converts stored private key bytes into private key instance
	^&lt;RSAPrivateKey | DSAPrivateKey&gt;
"
	| type stream class |
	class := self privateKeyAlgorithm privateKeyClass.
	type := PKCS8 module find: class asn1TypeName.
	stream := DERStream with: self privateKey.
	stream reset.
	^(class pkcs8FromMarshalingOutput: (stream unmarshalObjectType: type))
		algorithmIdentifier: self algorithmIdentifier;
		yourself</body>

<body package="PKCS8" selector="key:">key: key
"Converts a private key instance into bytes and stores them
	key &lt;RSAPrivateKey | DSAPrivateKey&gt;
"
	| stream |
	stream := DERStream on: ByteArray new.
	stream
		marshalObject: key pkcs8MarshalingInput
		withType: (PKCS8 module find: key class asn1TypeName).
	self	privateKeyAlgorithm: key algorithmIdentifier;
		privateKey: stream contents</body>
</methods>

<methods>
<class-id>Security.PrivateKeyInfo</class-id> <category>marshaling</category>

<body package="PKCS8" selector="privateKey">privateKey
	^privateKey</body>

<body package="PKCS8" selector="privateKey:">privateKey: aByteArray
	privateKey := aByteArray</body>

<body package="PKCS8" selector="privateKeyAlgorithm">privateKeyAlgorithm
	^privateKeyAlgorithm</body>

<body package="PKCS8" selector="privateKeyAlgorithm:">privateKeyAlgorithm: anAlgorithmIdentifier
	privateKeyAlgorithm := anAlgorithmIdentifier</body>

<body package="PKCS8" selector="version">version
	^version ifNil: [ 0 "That's the only standardized version for now anyway" ]</body>

<body package="PKCS8" selector="version:">version: aInteger
	version := aInteger</body>
</methods>

<methods>
<class-id>Security.PrivateKeyInfo</class-id> <category>testing</category>

<body package="PKCS8" selector="isDSA">isDSA

	^self algorithmIdentifier isDSA</body>

<body package="PKCS8" selector="isRSA">isRSA

	^self algorithmIdentifier isRSA</body>
</methods>

<methods>
<class-id>Security.PrivateKeyInfo</class-id> <category>writing</category>

<body package="PKCS8" selector="writeOn:">writeOn: aStream

	PKCS8 write: self on: aStream</body>
</methods>

<methods>
<class-id>Security.PrivateKeyInfo class</class-id> <category>accessing</category>

<body package="PKCS8" selector="asn1TypeName">asn1TypeName

	^#PrivateKeyInfo</body>
</methods>

<methods>
<class-id>Security.PrivateKeyInfo class</class-id> <category>initialize-release</category>

<body package="PKCS8" selector="initialize">initialize
	" self initialize "

	self register</body>

<body package="PKCS8" selector="register">register
	PKCS8 register: self.</body>

<body package="PKCS8" selector="registerAsn1TypesIn:">registerAsn1TypesIn: module
"
	PrivateKeyInfo ::= SEQUENCE {
 		version Version,
		privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
		privateKey PrivateKey,
		attributes [0] IMPLICIT Attributes OPTIONAL }
	Version ::= INTEGER
	PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
	PrivateKey ::= OCTET STRING
	Attributes ::= SET OF Attribute
"
	module SET: #Attributes OF: #ANY.	"Attribute is a complex beast from deep bowels of X-series spec hell. To be continued."

	( module SEQUENCE: self asn1TypeName )
		addElement: #version type: #INTEGER;
		addElement: #privateKeyAlgorithm type: #AlgorithmIdentifier;
		addElement: #privateKey type:  #OCTET_STRING; 
		addOptionalElement: #attributes type: #Attributes tag: 0 tagging: #implicit;
		mapping: self</body>
</methods>

<methods>
<class-id>Security.PrivateKeyInfo class</class-id> <category>instance creation</category>

<body package="PKCS8" selector="key:">key: key
"Creates an instance for a given private key
	key &lt;RSAPrivateKey | DSAPrivateKey&gt;
	^&lt;PrivateKeyInfo&gt;
"
	^self new key: key</body>

<body package="PKCS8" selector="readFrom:">readFrom: stream
"Read an instance from the stream.
	stream &lt;Stream&gt; a readable byte stream with DER encoded instance
	^&lt;PrivateKeyInfo&gt;
"
	^PKCS8 read: self asn1TypeName from: stream</body>

<body package="PKCS8" selector="readKeyFrom:">readKeyFrom: stream
"Read key from the stream
	stream &lt;Stream&gt; a readable byte stream with PKCS#8 encoding of the key
	^&lt;RSAPrivateKey | DSAPrivateKey&gt;
"
	^(self readFrom: stream) key</body>

<body package="PKCS8" selector="readKeyPEMFrom:">readKeyPEMFrom: stream
"Read a key from the stream
	stream &lt;Stream&gt; a readable character stream with PEM armored PKCS#8 encoding of the key
	^&lt;RSAPrivateKey | DSAPrivateKey&gt;
"
	^(self readPEMFrom: stream) key</body>

<body package="PKCS8" selector="readPEMFrom:">readPEMFrom: stream 
"Read an instance from the stream
	stream &lt;Stream&gt; a readable character stream with PEM armored DER encoding of the instance
	^&lt;PrivateKeyInfo&gt;
"
	^PKCS8 readPEM: self asn1TypeName from: stream</body>
</methods>

<methods>
<class-id>Security.PBEParameter</class-id> <category>marshaling</category>

<body package="PKCS8" selector="iterationCount">iterationCount
	^iterationCount ifNil: [ PBC defaultCount ]</body>

<body package="PKCS8" selector="iterationCount:">iterationCount: anObject
	iterationCount := anObject</body>
</methods>

<methods>
<class-id>Security.PBEParameter</class-id> <category>accessing</category>

<body package="PKCS8" selector="count">count

	^self iterationCount</body>

<body package="PKCS8" selector="count:">count: anInteger

	self iterationCount: anInteger</body>

<body package="PKCS8" selector="salt">salt
	^salt</body>

<body package="PKCS8" selector="salt:">salt: anObject
	salt := anObject</body>
</methods>

<methods>
<class-id>Security.PBEParameter class</class-id> <category>accessing</category>

<body package="PKCS8" selector="asn1TypeName">asn1TypeName
	^#PBEParameter</body>
</methods>

<methods>
<class-id>Security.PBEParameter class</class-id> <category>initialize-release</category>

<body package="PKCS8" selector="initialize">initialize
	" self initialize "

	self register</body>

<body package="PKCS8" selector="register">register
	PKCS8 register: self.</body>

<body package="PKCS8" selector="registerAsn1TypesIn:">registerAsn1TypesIn: module
"RFC 2898, A.3 PBES1:
For each OID, the parameters field associated with the OID in an AlgorithmIdentifier shall have type PBEParameter:

	PBEParameter ::= SEQUENCE {
		salt OCTET STRING (SIZE(8)),
		iterationCount INTEGER }
"
	( module SEQUENCE: self asn1TypeName )
		addElement: #salt type: #OCTET_STRING;
		addElement: #iterationCount type:  #INTEGER; 
		mapping: self</body>
</methods>

<methods>
<class-id>Security.PBEParameter class</class-id> <category>instance creation</category>

<body package="PKCS8" selector="salt:count:">salt: sNumber count: icNumber

	^self new
		salt: sNumber;
		count: icNumber;
		yourself</body>
</methods>

<methods>
<class-id>Security.EncryptedPrivateKeyInfo</class-id> <category>marshaling</category>

<body package="PKCS8" selector="encryptedData">encryptedData
	^encryptedData</body>

<body package="PKCS8" selector="encryptedData:">encryptedData: aByteArray
	encryptedData := aByteArray</body>

<body package="PKCS8" selector="encryptionAlgorithm">encryptionAlgorithm
	^encryptionAlgorithm ifNil: [ encryptionAlgorithm := self class defaultAlgorithmIdentifier ]</body>

<body package="PKCS8" selector="encryptionAlgorithm:">encryptionAlgorithm: anAlgorithmIdentifier
	encryptionAlgorithm := anAlgorithmIdentifier</body>
</methods>

<methods>
<class-id>Security.EncryptedPrivateKeyInfo</class-id> <category>writing</category>

<body package="PKCS8" selector="writeOn:">writeOn: aStream

	PKCS8 write: self on: aStream.</body>
</methods>

<methods>
<class-id>Security.EncryptedPrivateKeyInfo</class-id> <category>accessing</category>

<body package="PKCS8" selector="algorithmIdentifier">algorithmIdentifier

	^self encryptionAlgorithm</body>

<body package="PKCS8" selector="algorithmIdentifier:">algorithmIdentifier: identifier

	self encryptionAlgorithm: identifier</body>
</methods>

<methods>
<class-id>Security.EncryptedPrivateKeyInfo</class-id> <category>private</category>

<body package="PKCS8" selector="decrypt:password:">decrypt: bytes password: password

	^self algorithmIdentifier encryptionAlgorithm
		decrypt: bytes 
		password: password
		parameters: self algorithmIdentifier parameters</body>

<body package="PKCS8" selector="encrypt:password:">encrypt: bytes password: password

	^self algorithmIdentifier encryptionAlgorithm
		encrypt: bytes
		password: password
		parameters: self algorithmIdentifier parameters</body>
</methods>

<methods>
<class-id>Security.EncryptedPrivateKeyInfo</class-id> <category>services</category>

<body package="PKCS8" selector="key:password:">key: key password: password
"Conceal the key in 'encryptedData' using provided password.
	key &lt;RSAPrivateKey | DSAPrivateKey&gt;
	password &lt;ByteArray&gt;
"
	self keyInfo: (PrivateKeyInfo key: key) password: password</body>

<body package="PKCS8" selector="keyInfo:password:">keyInfo: info password: password
"Conceal the key info in 'encryptedData' using provided password.
	info &lt;PrivateKeyInfo&gt;
	password &lt;ByteArray&gt;
"
	| stream |
	stream := DERStream on: (ByteArray new: 500).
	info writeOn: stream.	
	self encryptedData: ( self encrypt: stream contents password: password )</body>

<body package="PKCS8" selector="keyInfoPassword:">keyInfoPassword: password
"Extract the PrivateKeyInfo from 'encryptedData' using provided password.
	password &lt;ByteArray&gt;
	^&lt;PrivateKeyInfo&gt;
"
	| decrData |
	decrData := self decrypt: self encryptedData password: password.
	^PrivateKeyInfo readFrom: decrData readStream</body>

<body package="PKCS8" selector="keyPassword:">keyPassword: password
"Extract the private key from 'encryptedData' using provided password.
	password &lt;ByteArray&gt;
	^&lt;RSAPrivateKey | DSAPrivateKey&gt;
"
	^(self keyInfoPassword: password) key</body>
</methods>

<methods>
<class-id>Security.EncryptedPrivateKeyInfo class</class-id> <category>accessing</category>

<body package="PKCS8" selector="asn1TypeName">asn1TypeName

	^#EncryptedPrivateKeyInfo</body>

<body package="PKCS8" selector="defaultAlgorithmIdentifier">defaultAlgorithmIdentifier
"We need a fresh copy of the identifier every time, because for some algorithms it stores actual parameters used, e.g. salt.
	^&lt;AlgorithmIdentifier&gt; creates a new algorithm identifier for the default encryption algorithm to use for key encryption
"
	^self defaultAlgorithmIdentifierFactory value</body>

<body package="PKCS8" selector="defaultAlgorithmIdentifierFactory">defaultAlgorithmIdentifierFactory
"
	^&lt;BlockClosure&gt; creates the default encryption algorithm identifier to use for key encryption
"
	^defaultAlgorithmIdentifier ifNil: [ self defaultAlgorithmIdentifierFactoryValue ]</body>

<body package="PKCS8" selector="defaultAlgorithmIdentifierFactory:">defaultAlgorithmIdentifierFactory: block
"
	block &lt;BlockClosure&gt; creates the default encryption algorithm identifier to use for key encryption
"
	defaultAlgorithmIdentifier := block</body>

<body package="PKCS8" selector="defaultAlgorithmIdentifierFactoryValue">defaultAlgorithmIdentifierFactoryValue

	^[ AlgorithmIdentifier pbeWithSHA1AndDES_CBC ]</body>
</methods>

<methods>
<class-id>Security.EncryptedPrivateKeyInfo class</class-id> <category>initialize-release</category>

<body package="PKCS8" selector="initialize">initialize
	" self initialize "

	self register</body>

<body package="PKCS8" selector="register">register
	PKCS8 register: self.</body>

<body package="PKCS8" selector="registerAsn1TypesIn:">registerAsn1TypesIn: module
"
	EncryptedPrivateKeyInfo ::= SEQUENCE {
		encryptionAlgorithm EncryptionAlgorithmIdentifier,
		encryptedData EncryptedData }
	EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
	EncryptedData ::= OCTET STRING
"

	( module SEQUENCE: self asn1TypeName )
		addElement: #encryptionAlgorithm type: #AlgorithmIdentifier;
		addElement: #encryptedData type:  #OCTET_STRING; 
		mapping: self</body>
</methods>

<methods>
<class-id>Security.EncryptedPrivateKeyInfo class</class-id> <category>instance creation</category>

<body package="PKCS8" selector="key:password:">key: key password: password
"Create an instance concealing the key using provided password and default encryption algorithm.
	key &lt;RSAPrivateKey | DSAPrivateKey&gt;
	password &lt;ByteArray&gt;
	^&lt;EncryptedPrivateKeyInfo&gt;
"
	^self new key: key password: password; yourself</body>

<body package="PKCS8" selector="keyInfo:password:">keyInfo: info password: password
"Create an instance concealing the key info using provided password and default encryption algorithm.
	info &lt;PrivateKeyInfo&gt;
	password &lt;ByteArray&gt;
	^&lt;EncryptedPrivateKeyInfo&gt;
"
	^self new keyInfo: info password: password; yourself</body>

<body package="PKCS8" selector="pbeWithMD5AndDES_CBC">pbeWithMD5AndDES_CBC
"Create an instance configured to use DES and MD5.
	self pbeWithMD5AndDES_CBC
"
	^self new
		algorithmIdentifier: AlgorithmIdentifier pbeWithMD5AndDES_CBC;
		yourself</body>

<body package="PKCS8" selector="pbeWithSHA1AndDES_CBC">pbeWithSHA1AndDES_CBC
"Create an instance configured to use DES and SHA1.
 	self pbeWithSHA1AndDES_CBC
"
	^self new
		algorithm: AlgorithmIdentifier pbeWithSHA1AndDES_CBC;
		yourself</body>

<body package="PKCS8" selector="readFrom:">readFrom: stream
"Read an instance from the stream.
	stream &lt;Stream&gt; a readable byte stream with DER encoded instance
	^&lt;EncryptedPrivateKeyInfo&gt;
"
	^PKCS8 read: self asn1TypeName from: stream</body>

<body package="PKCS8" selector="readKeyFrom:password:">readKeyFrom: stream password: password
"Read an encrypted key from the stream using the provided password.
	stream &lt;Stream&gt; a readable byte stream with PKCS#8 encoding of the key
	password &lt;ByteArray&gt;
	^&lt;RSAPrivateKey | DSAPrivateKey&gt;
"
	^(self readFrom: stream) keyPassword: password</body>

<body package="PKCS8" selector="readKeyPEMFrom:password:">readKeyPEMFrom: stream password: password
"Read an encrypted key from the stream using the provided password.
	stream &lt;Stream&gt; a readable character stream with PEM armored PKCS#8 encoding of the key
	password &lt;ByteArray&gt;
	^&lt;RSAPrivateKey | DSAPrivateKey&gt;
"
	^(self readPEMFrom: stream) keyPassword: password</body>

<body package="PKCS8" selector="readPEMFrom:">readPEMFrom: stream
"Read an instance from the stream
	stream &lt;Stream&gt; a readable character stream with PEM armored DER encoding of the instance
	^&lt;EncryptedPrivateKeyInfo&gt;
"
	^PKCS8 readPEM: self asn1TypeName from: stream</body>
</methods>

<methods>
<class-id>Security.EncryptedPrivateKeyInfo class</class-id> <category>instance creation - OpenSSL</category>

<body package="PKCS8" selector="PBE_MD5_DES">PBE_MD5_DES
"OpenSSL style alias.
	self PBE_MD5_DES
"
	^self pbeWithMD5AndDES_CBC</body>

<body package="PKCS8" selector="PBE_SHA1_DES">PBE_SHA1_DES
"OpenSSL style alias.
	self PBE_SHA1_DES
"
	^self pbeWithSHA1AndDES_CBC</body>
</methods>

<methods>
<class-id>Security.RSAPrivateKey class</class-id> <category>accessing</category>

<body package="PKCS8" selector="asn1TypeName">asn1TypeName

	^#RSAPrivateKey</body>
</methods>

<methods>
<class-id>Security.RSAPrivateKey class</class-id> <category>private</category>

<body package="PKCS8" selector="errorNotRSAKey:">errorNotRSAKey: info

	^PKCS8Error new
		messageText: (
			#PKCS8NotRSAKey1p &lt;&lt; #security &gt;&gt; 'OID &lt;1p&gt; does not indicate RSA key!'
				expandMacrosWith: info algorithmIdentifier oid );
		parameter: info;
		raise</body>

<body package="PKCS8" selector="pkcs8FromMarshalingOutput:">pkcs8FromMarshalingOutput: aPrivateKey

	^aPrivateKey</body>
</methods>

<methods>
<class-id>Security.RSAPrivateKey class</class-id> <category>instance creation</category>

<body package="PKCS8" selector="readFrom:">readFrom: stream
"Read a key from a PKCS#8 encoded binary stream
	stream &lt;Stream&gt; a binary stream containing PKCS#8 encoded RSA private key
	^&lt;RSAPrivateKey&gt;
"
	| info |
	info := PrivateKeyInfo readFrom: stream.
	^info isRSA
		ifTrue: [ info key ]
		ifFalse: [ self errorNotRSAKey: info ]</body>

<body package="PKCS8" selector="readFrom:password:">readFrom: stream password: password
"Read a key from a PKCS#8 encoded binary stream
	stream &lt;Stream&gt; a binary stream containing PKCS#8 encoded RSA private key
	password &lt;ByteArray&gt; encryption password used to conceal the key
	^&lt;RSAPrivateKey&gt;
"
	| info |
	info := EncryptedPrivateKeyInfo readFrom: stream.
	info := info keyInfoPassword: password.
	^info isRSA
		ifTrue: [ info key ]
		ifFalse: [ self errorNotRSAKey: info ]</body>

<body package="PKCS8" selector="readPEMFrom:">readPEMFrom: stream
"Read a PKCS#8 encoded key in PEM style ascii armoring (Base-64 encoded with identifying header and footer lines).
	aStream &lt;ReadStream&gt; a character stream containing PEM/PKCS#8 encoded RSA private key
	^&lt;RSAPrivateKey&gt;
"
	| info |
	info := PrivateKeyInfo readPEMFrom: stream.
	^info isRSA
		ifTrue: [ info key ]
		ifFalse: [ self errorNotRSAKey: info ]</body>

<body package="PKCS8" selector="readPEMFrom:password:">readPEMFrom: stream password: password
"Read a key from a PKCS#8 encoded stream with PEM style ascii armoring (Base-64 encoded with identifying header and footer lines).
	stream &lt;Stream&gt; a character stream containing PEM armored, PKCS#8 encoded RSA private key
	password &lt;ByteArray&gt; encryption password used to conceal the key
	^&lt;RSAPrivateKey&gt;
"
	| info |
	info := EncryptedPrivateKeyInfo readPEMFrom: stream.
	info := info keyInfoPassword: password.
	^info isRSA
		ifTrue: [ info key ]
		ifFalse: [ self errorNotRSAKey: info ]</body>
</methods>

<methods>
<class-id>Security.RSAPrivateKey class</class-id> <category>initialize-release</category>

<body package="PKCS8" selector="registerAsn1TypesIn:">registerAsn1TypesIn: module
"PKCS #1 V2.1: RSA CRYPTOGRAPHY STANDARD (June 14, 2002), Appendix A.1, RSA key representation:
The object identifier rsaEncryption identifies RSA public and private keys as defined in Appendices A.1.1 and A.1.2. The parameters field associated with this OID in a value of
type AlgorithmIdentifier shall have a value of type NULL.

	pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
	rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 }

PKCS#11v2.20, section 12.6, Wrapping/unwrapping private keys:
RSA private keys are BER-encoded according to PKCS #1 s RSAPrivateKey ASN.1 type. This type requires values to be present for *all* the attributes specific to Cryptoki s RSA private key objects. In other words, if a Cryptoki library does not have values for an RSA private key's CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT2, and CKA_COEFFICIENT values, it cannot create an RSAPrivateKey BER-encoding of the key, and so it cannot prepare it for wrapping.

	RSAPrivateKey ::= SEQUENCE {
		version Version, -- shall be 0 for this version of the document, unless multi-prime is used, in which case it shall be 1
		modulus INTEGER, -- n
		publicExponent INTEGER, -- e
		privateExponent INTEGER, -- d
		prime1 INTEGER, -- p
		prime2 INTEGER, -- q
		exponent1 INTEGER, -- d mod (p-1)
		exponent2 INTEGER, -- d mod (q-1)
		coefficient INTEGER, -- (inverse of q) mod p
		otherPrimeInfos OtherPrimeInfos OPTIONAL
	}

	Version ::= INTEGER { two-prime(0), multi(1) }
		(CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --})

	OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
	OtherPrimeInfo ::= SEQUENCE {
		prime INTEGER, -- is a prime factor ri of n, where i &gt;= 3.
		exponent INTEGER, -- di = d mod (ri - 1).
		coefficient INTEGER -- is the CRT coefficient ti = (r1 * r2 * ... * ri-1)^-1 mod ri.
	}
"
	( module SEQUENCE: self asn1TypeName )
		addElement: #version type: #INTEGER;
		addElement: #n type: #INTEGER;
		addElement: #e type: #INTEGER;
		addElement: #d type: #INTEGER;
		addElement: #p type: #INTEGER;
		addElement: #q type: #INTEGER;
		addElement: #dp type: #INTEGER;
		addElement: #dq type: #INTEGER;
		addElement: #qInv type: #INTEGER;
		mapping: self</body>
</methods>

<methods>
<class-id>Security.RSAPrivateKey</class-id> <category>accessing</category>

<body package="PKCS8" selector="algorithmIdentifier">algorithmIdentifier

	^AlgorithmIdentifier rsaEncryption</body>
</methods>

<methods>
<class-id>Security.RSAPrivateKey</class-id> <category>private</category>

<body package="PKCS8" selector="algorithmIdentifier:">algorithmIdentifier: identifier</body>

<body package="PKCS8" selector="pkcs8MarshalingInput">pkcs8MarshalingInput

	^self</body>
</methods>

<methods>
<class-id>Security.RSAPrivateKey</class-id> <category>marshaling - asn1</category>

<body package="PKCS8" selector="version">version

	^(otherFactors isNil or: [ otherFactors isEmpty ])
		ifTrue: [0]
		ifFalse: [1]</body>

<body package="PKCS8" selector="version:">version: anInteger
"do nothing for now"</body>
</methods>

<methods>
<class-id>Security.RSAPrivateKey</class-id> <category>writing</category>

<body package="PKCS8" selector="writeOn:">writeOn: aStream
"Write the key on the stream
	stream &lt;Stream&gt; writable byte stream
"
	(PrivateKeyInfo key: self) writeOn: aStream</body>

<body package="PKCS8" selector="writeOn:password:">writeOn: stream password: password
"Write the key on the stream concealing it using provided password
	stream &lt;Stream&gt; writable byte stream
	password &lt;ByteArray&gt; password used to encrypt the key
"
	(EncryptedPrivateKeyInfo key: self password: password) writeOn: stream</body>
</methods>

<methods>
<class-id>Security.DSAPrivateKey class</class-id> <category>accessing</category>

<body package="PKCS8" selector="asn1TypeName">asn1TypeName
	^#DSAPrivateKey</body>
</methods>

<methods>
<class-id>Security.DSAPrivateKey class</class-id> <category>private</category>

<body package="PKCS8" selector="errorNotDSAKey:">errorNotDSAKey: info

	^PKCS8Error new
		messageText: (
			#PKCS8NotDSAKey1p &lt;&lt; #security &gt;&gt; 'OID &lt;1p&gt; does not indicate DSA key!'
				expandMacrosWith: info algorithmIdentifier oid);
		parameter: info;
		raise</body>

<body package="PKCS8" selector="pkcs8FromMarshalingOutput:">pkcs8FromMarshalingOutput: anInteger

	^self new x: anInteger</body>
</methods>

<methods>
<class-id>Security.DSAPrivateKey class</class-id> <category>instance creation</category>

<body package="PKCS8" selector="readFrom:">readFrom: aStream
"Read a key from a PKCS#8 encoded binary stream
	aStream &lt;ReadStream&gt; a binary stream containing PKCS#8 encoded DSA private key
	^&lt;DSAPrivateKey&gt;
"
	| info |
	info := PrivateKeyInfo readFrom: aStream.
	^info isDSA
		ifTrue: [ info key ]
		ifFalse: [ self errorNotDSAKey: info ]</body>

<body package="PKCS8" selector="readFrom:password:">readFrom: stream password: password
"Read a key from a PKCS#8 encoded binary stream
	stream &lt;Stream&gt; a binary stream containing PKCS#8 encoded DSA private key
	password &lt;ByteArray&gt; encryption password used to conceal the key
	^&lt;DSAPrivateKey&gt;
"
	| info |
	info := EncryptedPrivateKeyInfo readFrom: stream.
	info := info keyInfoPassword: password.
	^info isDSA
		ifTrue: [ info key ]
		ifFalse: [ self errorNotDSAKey: info ]</body>

<body package="PKCS8" selector="readPEMFrom:">readPEMFrom: aStream
"Read a PKCS#8 encoded key in PEM style ascii armoring (Base-64 encoded with identifying header and footer lines).
	aStream &lt;ReadStream&gt; a character stream containing PEM/PKCS#8 encoded DSA private key
	^&lt;DSAPrivateKey&gt;
"
	| info |
	info := PrivateKeyInfo readPEMFrom: aStream.
	^info isDSA
		ifTrue: [ info key ]
		ifFalse: [ self errorNotDSAKey: info ]</body>

<body package="PKCS8" selector="readPEMFrom:password:">readPEMFrom: stream password: password
"Read a key from a PKCS#8 encoded stream with PEM style ascii armoring (Base-64 encoded with identifying header and footer lines).
	stream &lt;Stream&gt; a character stream containing PEM armored, PKCS#8 encoded DSA private key
	password &lt;ByteArray&gt; encryption password used to conceal the key
	^&lt;DSAPrivateKey&gt;
"
	| info |
	info := EncryptedPrivateKeyInfo readPEMFrom: stream.
	info := info keyInfoPassword: password.
	^info isDSA
		ifTrue: [ info key ]
		ifFalse: [ self errorNotDSAKey: info ]</body>
</methods>

<methods>
<class-id>Security.DSAPrivateKey class</class-id> <category>initialize-release</category>

<body package="PKCS8" selector="registerAsn1TypesIn:">registerAsn1TypesIn: module
"PKCS#11v2.20, section 12.6, Wrapping/unwrapping private keys:
The object identifiers for the required algorithm identifiers are as follows:

	id-dsa OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 1 }

These parameters for the algorithm identifiers have the following types, respectively:

    Dss-Parms ::= SEQUENCE {
        p INTEGER,
        q INTEGER,
        g INTEGER
    }

* DSA private keys are represented as BER-encoded ASN.1 type INTEGER.

Earlier drafts of PKCS #11 Version 2.0 and Version 2.01 used the object identifier

	DSA OBJECT IDENTIFIER ::= { algorithm 12 }
	algorithm OBJECT IDENTIFIER ::= { iso(1) identifier-organization(3) oiw(14) secsig(3) algorithm(2) }

with associated parameters

	DSAParameters ::= SEQUENCE {
		prime1 INTEGER, -- modulus p
		prime2 INTEGER, -- modulus q
		base INTEGER -- base g
	}

for wrapping DSA private keys. Note that although the two structures for holding DSA parameters appear identical when instances of them are encoded, the two corresponding object identifiers are different.
"

	module INTEGER: self asn1TypeName</body>
</methods>

<methods>
<class-id>Security.DSAPrivateKey</class-id> <category>accessing</category>

<body package="PKCS8" selector="algorithmIdentifier">algorithmIdentifier

	^AlgorithmIdentifier dsa
		parameters: (DSSParameters new p: self p; q: self q; g: self g; yourself );
		yourself</body>
</methods>

<methods>
<class-id>Security.DSAPrivateKey</class-id> <category>private</category>

<body package="PKCS8" selector="algorithmIdentifier:">algorithmIdentifier: identifier

	^identifier parameters ifNotNil: [ :params |
		self	p: params p;
			q: params q;
			g: params g ]</body>

<body package="PKCS8" selector="pkcs8MarshalingInput">pkcs8MarshalingInput

	^self x</body>
</methods>

<methods>
<class-id>Security.DSAPrivateKey</class-id> <category>writing</category>

<body package="PKCS8" selector="writeOn:">writeOn: aStream
"Write the key on the stream
	stream &lt;Stream&gt; writable byte stream
"
	(PrivateKeyInfo key: self) writeOn: aStream</body>

<body package="PKCS8" selector="writeOn:password:">writeOn: stream password: password
"Write the key on the stream concealing it using provided password
	stream &lt;Stream&gt; writable byte stream
	password &lt;ByteArray&gt; password used to encrypt the key
"
	(EncryptedPrivateKeyInfo key: self password: password) writeOn: stream</body>
</methods>

<methods>
<class-id>Security.PBC</class-id> <category>private</category>

<body package="PKCS8" selector="decrypt:password:parameters:">decrypt: bytes password: password parameters: parameters
"Decrypt the bytes using the provided password and parameters.
	bytes &lt;ByteArray&gt; 
	password &lt;ByteArray&gt;
	parameters &lt;PBEParameter&gt;
	^&lt;ByteArray&gt;
"
	^self	count: parameters iterationCount;
		decrypt: bytes
		password: password
		salt: parameters salt</body>

<body package="PKCS8" selector="encrypt:password:parameters:">encrypt: bytes password: password parameters: parameters
"Encrypt the bytes using the provided password and parameters.
Note that parameters can get updated as a side-effect of this method (e.g. with auto-generated salt)
	bytes &lt;ByteArray&gt; 
	password &lt;ByteArray&gt;
	parameters &lt;PBEParameter&gt;
	^&lt;ByteArray&gt;
"
	self count: parameters iterationCount.
	^parameters salt
		ifNil: [ | asc |
			asc := self encrypt: bytes password: password.
			parameters salt: asc key. "SIDE-EFFECT!"
			asc value ]
		ifNotNil: [ :salt |
			self encrypt: bytes password: password salt: parameters salt ]</body>
</methods>

<initialize>
<class-id>Security.PKCS8</class-id>
</initialize>

<initialize>
<class-id>Security.AlgorithmIdentifier</class-id>
</initialize>

<initialize>
<class-id>Security.DSSParameters</class-id>
</initialize>

<initialize>
<class-id>Security.PrivateKeyInfo</class-id>
</initialize>

<initialize>
<class-id>Security.PBEParameter</class-id>
</initialize>

<initialize>
<class-id>Security.EncryptedPrivateKeyInfo</class-id>
</initialize>

<do-it>"Imported Classes:"</do-it>

<do-it>self error: 'Attempting to file-in parcel imports.  Choose terminate or close'</do-it>

<class>
<name>Object</name>
<environment>Core</environment>
<super></super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Kernel-Objects</category>
<attributes>
<package>Kernel-Objects</package>
</attributes>
</class>

<class>
<name>RSAPrivateKey</name>
<environment>Security</environment>
<super>Security.RSAKey</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>d e p q dP dQ qInv otherFactors </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Security-Ciphers</category>
<attributes>
<package>RSA</package>
</attributes>
</class>

<class>
<name>DSAPrivateKey</name>
<environment>Security</environment>
<super>Security.DSAKey</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>x </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Security-Ciphers</category>
<attributes>
<package>DSA</package>
</attributes>
</class>

<class>
<name>PBC</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>count v1 prf cipher mac </inst-vars>
<class-inst-vars>defaultCount </class-inst-vars>
<imports></imports>
<category>PBC</category>
<attributes>
<package>PKCS5</package>
</attributes>
</class>

<class>
<name>Error</name>
<environment>Core</environment>
<super>Core.Exception</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Kernel-Exception Handling</category>
<attributes>
<package>Kernel-Exception Handling</package>
</attributes>
</class>

</st-source>
