cryptostore-0.3.1.0/0000755000000000000000000000000007346545000012437 5ustar0000000000000000cryptostore-0.3.1.0/ChangeLog.md0000644000000000000000000000671607346545000014622 0ustar0000000000000000# Revision history for cryptostore ## 0.3.1.0 - 2024-05-05 * Strict validation of GCM/CCM authentication tag length ## 0.3.0.1 - 2023-06-25 * Add optional flag to use crypton instead of cryptonite ## 0.3.0.0 - 2023-01-14 * API change in PKCS5, PKCS8 and PKCS12 modules to handle better password-based encryption derived from an empty password. All encryption/decryption functions now expect an opaque `ProtectionPassword` data type. Conversion functions `toProtectionPassword` and `fromProtectionPassword` are provided. Additionnally in the PKCS12 module, the type `OptProtected` is replaced with `OptAuthenticated` when dealing with password integrity. Similarly at that level, function `recover` is to be replaced with `recoverAuthenticated`. * Added support for KMAC (Keccak Message Authentication Code) in CMS authenticated data, through constructors `KMAC_SHAKE128` and `KMAC_SHAKE256`. * CMS key agreement now supports derivation with HKDF along with X9.63. Data type `KeyAgreementParams` is modified to include a KDF instead of simply the digest algorithm. HKDF has assigned OIDs only for standard DH and cannot be used with cofactor DH. * Added CMS utility functions to deal with the `signingTime` attribute. * Changed `withSignerCertificate` validation callback API to include the `signingTime` value when available. ## 0.2.3.0 - 2022-11-05 * Fix RC2 on big-endian architectures ## 0.2.2.0 - 2022-04-16 * Fix buffer overrun in `pkcs12Derive` ## 0.2.1.0 - 2019-10-13 * Added CMS fuctions `contentInfoToDER` and `berToContentInfo` in order to generate and parse raw ASN.1. * Implementation of AES key wrap had some optimizations. * SHAKE hash algorithms now allow arbitrary output lengths. Lengths that are very small decrease security. A protection is added so that attempts to use lengths which are too small fail, although the criteria are conservative. Generating and parsing content has no restriction. ## 0.2.0.0 - 2019-03-24 * Added functions `toNamedCredential` and `fromNamedCredential` to handle PKCS#12 elements with an alias (friendly name). * Functions `fromCredential` and `fromNamedCredential` now generate PKCS#12 elements with the `localKeyId` attribute. * Function `toCredential` is now able to locate the leaf certificate and issuers more reliably. * Algorithms X25519, X448, Ed25519 and Ed448 are now supported. * CMS functions `digestVerify` and `verifySignedData` now return an `Either` instead of a `Maybe`. Errors `DigestMismatch` and `SignatureNotVerified` are added to report failures. * CMS types `SignedData`, `DigestedData` and `AuthenticatedData` now retain the encapsulated content in encoded form (with type alias `EncapsulatedContent`) instead of a decoded and parsed `ContentInfo`. The `ContentInfo` is parsed and provided only when successfully unwrapping the encapsulated type. * The CMS interface is transformed to support detached content. CMS types now have a type parameter to distinguish between a direct reference to the encapsulated or encrypted content, and the `Encap` indirection which denotes an attached or detached content. Functions building CMS types do not return the `ContentInfo` directly anymore, but an intermediate type to be fed into `toAttachedCI` or `toDetachedCI`. Reverse transformation is possible with utility functions `fromAttached` and `fromDetached` when unwrapping a `ContentInfo`. ## 0.1.0.0 - 2018-09-23 * First version. Released on an unsuspecting world. cryptostore-0.3.1.0/LICENSE0000644000000000000000000000277507346545000013457 0ustar0000000000000000Copyright (c) 2018-2024, Olivier Chéron All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Olivier Chéron nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. cryptostore-0.3.1.0/README.md0000644000000000000000000003022507346545000013720 0ustar0000000000000000# cryptostore [![Build Status](https://github.com/ocheron/cryptostore/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/ocheron/cryptostore/actions/workflows/tests.yml) [![BSD](https://img.shields.io/badge/License-BSD-blue)](https://en.wikipedia.org/wiki/BSD_licenses) [![Haskell](https://img.shields.io/badge/Language-Haskell-lightgrey)](https://haskell.org/) This package allows to read and write cryptographic objects to/from ASN.1. Currently the following is implemented: * Reading and writing private keys with optional encryption (this extends [x509-store](https://hackage.haskell.org/package/x509-store) API) * Reading and writing public keys, certificates and CRLs * PKCS #12 container format (password-based only) * Many parts of Cryptographic Message Syntax Please have a look at the examples below as well as some warnings about cryptographic algorithms. ## Private Keys The API to read and write private keys is available in module `Crypto.Store.PKCS8`. When encrypting, some types and functions from module `Crypto.Store.PKCS5` are also necessary. Reading a private key from disk: ```haskell > :set -XOverloadedStrings > :m Crypto.Store.PKCS8 > (key : _) <- readKeyFile "/path/to/privkey.pem" -- assuming single key > recover "mypassword" key Right (PrivKeyRSA ...) ``` Generating a private key and writing to disk, without encryption: ```haskell > :m Crypto.PubKey.RSA Crypto.Store.PKCS8 Data.X509 > privKey <- PrivKeyRSA . snd <$> generate (2048 `div` 8) 0x10001 > writeKeyFile PKCS8Format "/path/to/privkey.pem" [privKey] ``` Generating a private key and writing to disk, with password-based encryption: ```haskell > :set -XOverloadedStrings > :m Crypto.PubKey.RSA Crypto.Store.PKCS8 Data.X509 Crypto.Store.PKCS5 > privKey <- PrivKeyRSA . snd <$> generate (2048 `div` 8) 0x10001 > salt <- generateSalt 16 > let kdf = PBKDF2 salt 200000 Nothing PBKDF2_SHA256 > encParams <- generateEncryptionParams (CBC AES256) > let pbes = PBES2 (PBES2Parameter kdf encParams) > writeEncryptedKeyFile "/path/to/privkey.pem" pbes "mypassword" privKey Right () ``` Parameters used in this example are AES-256-CBC as cipher, PBKDF2 as key-derivation function, with a 16-byte salt, 200,000 iterations and SHA-256 as pseudorandom function. ## Public Keys and Signed Objects Module `Crypto.Store.X509` provides functions to read/write PEM files containing public keys, X.509 certificates and CRLs. These files are never encrypted. Reading a public key and certificate from disk: ```haskell > :m Data.X509 Crypto.Store.X509 > readPubKeyFile "/path/to/pubkey.pem" [PubKeyRSA ...] > readSignedObject "/path/to/cert.pem" :: IO [SignedCertificate] [SignedExact ...] ``` Writing back to disk: ```haskell > :m Crypto.Store.X509 > writePubKeyFile "/path/to/pubkey.pem" [pubKey] > writeSignedObject "/path/to/cert.pem" [cert] ``` ## PKCS #12 PKCS #12 is a complex format with multiple layers of protection, providing usually both privacy and integrity, with a single password for all or not. The API to read PKCS #12 files requires some password at each layer. This API is available in module `Crypto.Store.PKCS12`. Reading a binary PKCS #12 file using a single password doing both integrity and privacy (usual case): ```haskell > :set -XOverloadedStrings > :m Crypto.Store.PKCS12 > Right p12 <- readP12File "/path/to/file.p12" > let Right (password, pkcs12) = recoverAuthenticated "mypassword" p12 > let Right contents = recover password (unPKCS12 pkcs12) > getAllSafeX509Certs contents [SignedExact {getSigned = ...}] > recover password (getAllSafeKeys contents) Right [PrivKeyRSA ...] ``` Reading a binary PKCS #12 file using distinct integrity and privacy passwords: ```haskell > :set -XOverloadedStrings > :m Crypto.Store.PKCS12 > Right p12 <- readP12File "/path/to/file.p12" > let Right (_, pkcs12) = recoverAuthenticated "myintegritypassword" p12 > let Right contents = recover "myprivacypassword" (unPKCS12 pkcs12) > getAllSafeX509Certs contents [SignedExact {getSigned = ...}] > recover "myprivacypassword" (getAllSafeKeys contents) Right [PrivKeyRSA ...] ``` Generating a PKCS #12 file containing a private key: ```haskell > :set -XOverloadedStrings -- Generate a private key > :m Crypto.PubKey.RSA Data.X509 > privKey <- PrivKeyRSA . snd <$> generate (2048 `div` 8) 0x10001 -- Put the key inside a bag > :m Crypto.Store.PKCS12 Crypto.Store.PKCS8 Crypto.Store.PKCS5 Crypto.Store.CMS > let attrs = setFriendlyName "Some Key" [] > keyBag = Bag (KeyBag $ FormattedKey PKCS8Format privKey) attrs > contents = SafeContents [keyBag] -- Encrypt the contents > salt <- generateSalt 16 > let kdf = PBKDF2 salt 200000 Nothing PBKDF2_SHA256 > encParams <- generateEncryptionParams (CBC AES256) > let pbes = PBES2 (PBES2Parameter kdf encParams) > Right pkcs12 = encrypted pbes "mypassword" contents -- Save to PKCS #12 with integrity protection (same password) > salt' <- generateSalt 16 > let iParams = (DigestAlgorithm SHA256, PBEParameter salt' 200000) > writeP12File "/path/to/privkey.p12" iParams "mypassword" pkcs12 Right () ``` The API also provides functions to generate/extract a pair containing a private key and a certificate chain. This pair is the type alias `Credential` in `tls`. ```haskell > :set -XOverloadedStrings > :m Crypto.Store.PKCS12 Crypto.Store.PKCS8 Crypto.Store.PKCS5 Crypto.Store.CMS -- Read PKCS #12 content as credential > Right p12 <- readP12File "/path/to/file.p12" > let Right (_, pkcs12) = recoverAuthenticated "myintegritypassword" p12 > let Right (Just cred) = recover "myprivacypassword" (toCredential pkcs12) > cred (CertificateChain [...], PrivKeyRSA (...)) -- Scheme to reencrypt the key > saltK <- generateSalt 16 > let kdfK = PBKDF2 saltK 200000 Nothing PBKDF2_SHA256 > encParamsK <- generateEncryptionParams (CBC AES256) > let sKey = PBES2 (PBES2Parameter kdfK encParamsK) -- Scheme to reencrypt the certificate chain > saltC <- generateSalt 8 > let kdfC = PBKDF2 saltC 100000 Nothing PBKDF2_SHA256 > encParamsC <- generateEncryptionParams (CBC AES128) > let sCert = PBES2 (PBES2Parameter kdfC encParamsC) -- Write the content back to a new file > let Right pkcs12' = fromCredential (Just sCert) sKey "myprivacypassword" cred > salt <- generateSalt 16 > let iParams = (DigestAlgorithm SHA256, PBEParameter salt 200000) > writeP12File "/path/to/newfile.p12" iParams "myintegritypassword" pkcs12' ``` Variants `toNamedCredential` and `fromNamedCredential` are also available when PKCS #12 elements need an alias (friendly name). ## Cryptographic Message Syntax The API to read and write CMS content is available in `Crypto.Store.CMS`. The main data type `ContentInfo` represents a CMS structure. Implemented content types are: * data * signed data * enveloped data * digested data * encrypted data * authenticated data * and authenticated-enveloped data Notable omissions: * streaming * compressed data * and S/MIME external format (only PEM is supported, i.e. the textual encoding of [RFC 7468](https://tools.ietf.org/html/rfc7468)) ### Enveloped data The following examples generate a CMS structure enveloping some data to a password recipient, then decrypt the data to recover the content. #### Generating enveloped data ```haskell > :set -XOverloadedStrings > :m Crypto.Store.CMS -- Input content info > let info = DataCI "Hi, what will you need from the cryptostore?" -- Content encryption will use AES-128-CBC > ceParams <- generateEncryptionParams (CBC AES128) > ceKey <- generateKey ceParams :: IO ContentEncryptionKey -- Encrypt the Content Encryption Key with a Password Recipient Info, -- i.e. a KDF will derive the Key Encryption Key from a password -- that the recipient will need to know > salt <- generateSalt 16 > let kdf = PBKDF2 salt 200000 Nothing PBKDF2_SHA256 > keParams <- generateEncryptionParams (CBC AES128) > let pri = forPasswordRecipient "mypassword" kdf (PWRIKEK keParams) -- Generate the enveloped structure for this single recipient. Encrypted -- content is kept attached in the structure. > Right envelopedData <- envelopData mempty ceKey ceParams [pri] [] info > let envelopedCI = toAttachedCI envelopedData > writeCMSFile "/path/to/enveloped.pem" [envelopedCI] ``` #### Opening the enveloped data ```haskell > :set -XOverloadedStrings > :m Crypto.Store.CMS -- Then this recipient just has to read the file and recover enveloped -- content using the password > [EnvelopedDataCI envelopedEncapData] <- readCMSFile "/path/to/enveloped.pem" > envelopedData <- fromAttached envelopedEncapData > openEnvelopedData (withRecipientPassword "mypassword") envelopedData Right (DataCI "Hi, what will you need from the cryptostore?") ``` ### Signed data The following examples generate a CMS structure signing data with an RSA key and certificate, then verify the signature and recover the content. #### Signing data ```haskell > :set -XOverloadedStrings > :m Crypto.Store.CMS Data.X509 Crypto.Store.X509 Crypto.Store.PKCS8 -- Input content info > let info = DataCI "Some trustworthy content" -- Read signer certificate and private key > (key : _) <- readKeyFile "/path/to/privkey.pem" -- assuming single key > let Right priv = recover "mypassword" key > chain <- readSignedObject "/path/to/cert.pem" :: IO [SignedCertificate] > let cert = CertificateChain chain -- Signature will use RSASSA-PSS and SHA-256 > let sha256 = DigestAlgorithm SHA256 > let params = PSSParams sha256 (MGF1 sha256) 16 -- Generate the signed structure with a single signer. Signed content is -- kept attached in the structure. > let signer = certSigner (RSAPSS params) priv cert (Just []) [] > Right signedData <- signData [signer] info > let signedCI = toAttachedCI signedData > writeCMSFile "/path/to/signed.pem" [signedCI] ``` #### Verifying signed data ```haskell -- Read certificate authorities to be trusted for validation > :m Crypto.Store.X509 Data.X509.CertificateStore > store <- makeCertificateStore <$> readSignedObject "/path/to/cacert.pem" -- Assume we will not verify the signer FQHN. Instead the certificate could be -- related to an identity from which we received the signed data. > :m Data.Default.Class Data.X509 Data.X509.Validation > let validateNoFQHN = validate HashSHA256 def def { checkFQHN = False } > let noServiceID = (undefined, undefined) -- Read the signed data and validate it to recover the content > :m Crypto.Store.CMS Data.Default.Class > [SignedDataCI signedEncapData] <- readCMSFile "/path/to/signed.pem" > signedData <- fromAttached signedEncapData > let doValidation _ chain = null <$> validateNoFQHN store def noServiceID chain > verifySignedData (withSignerCertificate doValidation) signedData Right (DataCI "Some trustworthy content") ``` ## Algorithms and security For compatibility reasons cryptostore implements many outdated algorithms that are still in use in data formats. Please check your security requirements. New applications should favor PBKDF2 or Scrypt and AEAD ciphers. Additionally, the package is designed exclusively for store and forward scenarios, as most algorithms will not be perfectly safe for interactive use. ECDSA signature generation uses the generic ECC implementation from cryptonite and could leak the private key under timing attack. A padding oracle on CBC-encrypted ciphertext allows to recover the plaintext. ## Design Main dependencies are: * [cryptonite](https://hackage.haskell.org/package/cryptonite) implementation of public-key systems, symmetric ciphers, KDFs, MAC, and one-way hash functions * [asn1-types](https://hackage.haskell.org/package/asn1-types) and [asn1-encoding](https://hackage.haskell.org/package/asn1-encoding) to encode and decode ASN.1 content * [pem](https://hackage.haskell.org/package/pem) to read and write PEM files * [x509](https://hackage.haskell.org/package/x509) contains the certificate and private-key data types Internally the ASN.1 parser used is a local implementation extending the code of [asn1-parse](https://hackage.haskell.org/package/asn1-parse). This extension is able to parse `ASN1Repr`, i.e. a stream of ASN.1 tags associated with the binary decoding events the tags were originated from. Similarly generation of ASN.1 content does not use the `ASN1S` type but an extension which is able to encode a stream where some parts have already been encoded. Retaining the original BER/DER encoding is required when incorporating MACed or signed content. cryptostore-0.3.1.0/Setup.hs0000644000000000000000000000005607346545000014074 0ustar0000000000000000import Distribution.Simple main = defaultMain cryptostore-0.3.1.0/cryptostore.cabal0000644000000000000000000001017307346545000016022 0ustar0000000000000000name: cryptostore version: 0.3.1.0 synopsis: Serialization of cryptographic data types description: Haskell implementation of PKCS \#8, PKCS \#12 and CMS (Cryptographic Message Syntax). license: BSD3 license-file: LICENSE author: Olivier Chéron maintainer: olivier.cheron@gmail.com copyright: Olivier Chéron category: Cryptography, Codec homepage: https://github.com/ocheron/cryptostore bug-reports: https://github.com/ocheron/cryptostore/issues build-type: Simple extra-source-files: README.md ChangeLog.md tests/files/*.pem cabal-version: >=1.10 source-repository head type: git location: https://github.com/ocheron/cryptostore flag use_crypton description: Use crypton instead of cryptonite manual: True default: False library hs-source-dirs: src exposed-modules: Crypto.Store.CMS , Crypto.Store.Cipher.RC2 , Crypto.Store.Error , Crypto.Store.PKCS5 , Crypto.Store.KeyWrap.AES , Crypto.Store.KeyWrap.TripleDES , Crypto.Store.KeyWrap.RC2 , Crypto.Store.PKCS12 , Crypto.Store.PKCS8 , Crypto.Store.X509 other-modules: Crypto.Store.ASN1.Generate , Crypto.Store.ASN1.Parse , Crypto.Store.CMS.Algorithms , Crypto.Store.CMS.Attribute , Crypto.Store.CMS.Authenticated , Crypto.Store.CMS.AuthEnveloped , Crypto.Store.CMS.Digested , Crypto.Store.CMS.Encrypted , Crypto.Store.CMS.Enveloped , Crypto.Store.CMS.Info , Crypto.Store.CMS.OriginatorInfo , Crypto.Store.CMS.PEM , Crypto.Store.CMS.Signed , Crypto.Store.CMS.Type , Crypto.Store.CMS.Util , Crypto.Store.Cipher.RC2.Primitive , Crypto.Store.PEM , Crypto.Store.PKCS5.PBES1 , Crypto.Store.PKCS8.EC , Crypto.Store.Util -- other-extensions: build-depends: base >= 4.9 && < 5 , bytestring , basement , memory , pem >= 0.1 && < 0.3 , asn1-types >= 0.3.1 && < 0.4 , asn1-encoding >= 0.9 && < 0.10 , hourglass >= 0.2 if flag(use_crypton) build-depends: crypton , crypton-x509 , crypton-x509-validation else build-depends: cryptonite >=0.26 , x509 >= 1.7.5 , x509-validation >= 1.5 default-language: Haskell2010 ghc-options: -Wall test-suite test-cryptostore type: exitcode-stdio-1.0 hs-source-dirs: tests main-is: Main.hs other-modules: KeyWrap.AES , KeyWrap.TripleDES , KeyWrap.RC2 , CMS.Instances , CMS.Tests , Cipher.RC2 , PKCS12.Instances , PKCS12.Tests , PKCS8.Instances , PKCS8.Tests , Util , X509.Instances , X509.Tests build-depends: base >= 4.9 && < 5 , bytestring , asn1-types >= 0.3.1 && < 0.4 , memory , tasty , tasty-hunit , tasty-quickcheck , hourglass , pem , cryptostore if flag(use_crypton) build-depends: crypton , crypton-x509 else build-depends: cryptonite >=0.25 , x509 default-language: Haskell2010 ghc-options: -Wall cryptostore-0.3.1.0/src/Crypto/Store/ASN1/0000755000000000000000000000000007346545000016304 5ustar0000000000000000cryptostore-0.3.1.0/src/Crypto/Store/ASN1/Generate.hs0000644000000000000000000001114307346545000020372 0ustar0000000000000000-- | -- Module : Crypto.Store.ASN1.Generate -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- Generating ASN.1 module Crypto.Store.ASN1.Generate ( ASN1Stream , ASN1Elem() , ASN1P() , ASN1PS , asn1Container , gNull , gIntVal , gOID , gASN1String , gBMPString , gOctetString , gBitString , gASN1Time , gMany , gEncoded , optASN1S , encodeASN1S ) where import Data.ASN1.BinaryEncoding import Data.ASN1.BinaryEncoding.Raw import Data.ASN1.BitArray import Data.ASN1.Encoding import Data.ASN1.OID import Data.ASN1.Types import qualified Data.ByteArray as B import Data.ByteString (ByteString) import Time.Types (DateTime, TimezoneOffset) -- | A stream of ASN.1 elements. type ASN1Stream e = [e] -> [e] -- | Elements in an ASN.1 stream. class ASN1Elem e where -- | Create a container from an inner ASN.1 stream. asn1Container :: ASN1ConstructionType -> ASN1Stream e -> ASN1Stream e -- | Generate a list of ASN.1 elements. gMany :: [ASN1] -> ASN1Stream e -- | Generate one ASN.1 element. gOne :: ASN1 -> ASN1Stream e instance ASN1Elem ASN1 where asn1Container ty f = (Start ty :) . f . (End ty :) gMany = (++) gOne = (:) -- | Extend the 'ASN1' type to be able to encode to ASN.1 even when some parts -- of the stream have already been encoded. data ASN1P = ASN1Prim [ASN1] -- ^ Primitive elements (or constructed types that are fully terminated) | ASN1Container !ASN1ConstructionType [ASN1P] -- ^ Constructed type with inner structure kept | ASN1Encoded !ByteString -- ^ A part which has already been encoded instance ASN1Elem ASN1P where asn1Container ty f = (ASN1Container ty (f []) :) gMany asn1 = (ASN1Prim asn1 :) gOne = gMany . (:[]) -- | Prepend a list of 'ASN1P'. type ASN1PS = ASN1Stream ASN1P -- | Encode to ASN.1 a list of 'ASN1P' elements. Outer encoding will be DER, -- but partially encoded inner 'ASN1Encoded' elements many have any encoding. pEncode :: [ASN1P] -> ByteString pEncode x = let (_, f) = run x in f B.empty where run [] = (0, id) run (ASN1Prim asn1 : as) = (B.length p + r, B.append p . ps) where p = encodeASN1' DER asn1 (r, ps) = run as run (ASN1Encoded p : as) = (B.length p + r, B.append p . ps) where (r, ps) = run as run (ASN1Container ty children : as) = (B.length header + l + r, B.append header . p . ps) where (l, p) = run children (r, ps) = run as header = toByteString [Header $ ASN1Header cl tg True $ makeLen l] (cl, tg) = case ty of Container tyClass tyTag -> (tyClass, tyTag) Sequence -> (Universal, 0x10) Set -> (Universal, 0x11) makeLen len | len < 0x80 = LenShort len | otherwise = LenLong (nbBytes len) len nbBytes nb = if nb > 255 then 1 + nbBytes (nb `div` 256) else 1 -- | Generate a 'Null' ASN.1 element. gNull :: ASN1Elem e => ASN1Stream e gNull = gOne Null -- | Generate an 'IntVal' ASN.1 element. gIntVal :: ASN1Elem e => Integer -> ASN1Stream e gIntVal = gOne . IntVal -- | Generate an 'OID' ASN.1 element. gOID :: ASN1Elem e => OID -> ASN1Stream e gOID = gOne . OID -- | Generate an 'ASN1String' ASN.1 element. gASN1String :: ASN1Elem e => ASN1CharacterString -> ASN1Stream e gASN1String = gOne . ASN1String -- | Generate an @BMPString@ ASN.1 element. gBMPString :: ASN1Elem e => String -> ASN1Stream e gBMPString = gASN1String . asn1CharacterString BMP -- | Generate an 'OctetString' ASN.1 element. gOctetString :: ASN1Elem e => ByteString -> ASN1Stream e gOctetString = gOne . OctetString -- | Generate a 'BitString' ASN.1 element. gBitString :: ASN1Elem e => BitArray -> ASN1Stream e gBitString = gOne . BitString -- | Generate an 'ASN1Time' ASN.1 element. gASN1Time :: ASN1Elem e => ASN1TimeType -> DateTime -> Maybe TimezoneOffset -> ASN1Stream e gASN1Time a b c = gOne (ASN1Time a b c) -- | Generate ASN.1 for an optional value. optASN1S :: Maybe a -> (a -> ASN1Stream e) -> ASN1Stream e optASN1S Nothing _ = id optASN1S (Just val) fn = fn val -- | Generate ASN.1 for a part of the stream which is already encoded. gEncoded :: ByteString -> ASN1PS gEncoded = (:) . ASN1Encoded -- | Encode the ASN.1 stream to DER format (except for inner parts that are -- already encoded and may use another format). encodeASN1S :: ASN1PS -> ByteString encodeASN1S asn1 = pEncode (asn1 []) cryptostore-0.3.1.0/src/Crypto/Store/ASN1/Parse.hs0000644000000000000000000001771507346545000017725 0ustar0000000000000000-- | -- Module : Crypto.Store.ASN1.Parse -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- Parser combinators for ASN.1 stream. Similar to "Data.ASN1.Parse" but -- with the following additions: -- -- * Parsed stream is annotated, i.e. parser input is @('ASN1', e)@ instead of -- @'ASN1'@. Main motivation is to allow to parse a sequence of 'ASN1Repr' -- and hold the exact binary content that has been parsed. As consequence, -- no @getObject@ function is provided. Function 'withAnnotations' runs -- a parser and returns all annotations consumed in a monoid concatenation. -- -- * The parser implements 'Alternative' and 'MonadPlus'. -- -- * The 'fail' function returns a parse error so that pattern matching makes -- monadic parsing code easier to write. {-# LANGUAGE CPP #-} module Crypto.Store.ASN1.Parse ( ParseASN1 -- * run , runParseASN1State , runParseASN1State_ , runParseASN1 , runParseASN1_ , throwParseError -- * combinators , onNextContainer , onNextContainerMaybe , getNextContainer , getNextContainerMaybe , getNext , getNextMaybe , hasNext , getMany , withAnnotations ) where import Data.ASN1.Types import Data.Monoid import Control.Applicative import Control.Arrow (first) import Control.Monad (MonadPlus(..), liftM2) #if !(MIN_VERSION_base(4,13,0)) import Control.Monad.Fail as Fail #endif data State e = State [(ASN1, e)] !e -- | ASN1 parse monad newtype ParseASN1 e a = P { runP :: State e -> Either String (a, State e) } instance Functor (ParseASN1 e) where fmap f m = P (fmap (first f) . runP m) instance Applicative (ParseASN1 e) where pure a = P $ \s -> Right (a, s) (<*>) mf ma = P $ \s -> case runP mf s of Left err -> Left err Right (f, s2) -> case runP ma s2 of Left err -> Left err Right (a, s3) -> Right (f a, s3) instance Alternative (ParseASN1 e) where empty = throwParseError "empty" (<|>) = mplus instance Monad (ParseASN1 e) where return = pure (>>=) m1 m2 = P $ \s -> case runP m1 s of Left err -> Left err Right (a, s2) -> runP (m2 a) s2 #if !(MIN_VERSION_base(4,13,0)) fail = Fail.fail #endif instance MonadFail (ParseASN1 e) where fail = throwParseError instance MonadPlus (ParseASN1 e) where mzero = throwParseError "mzero" mplus m1 m2 = P $ \s -> case runP m1 s of Left _ -> runP m2 s success -> success get :: ParseASN1 e (State e) get = P $ \stream -> Right (stream, stream) put :: State e -> ParseASN1 e () put stream = P $ \_ -> Right ((), stream) -- | throw a parse error throwParseError :: String -> ParseASN1 e a throwParseError s = P $ \_ -> Left s wrap :: ASN1 -> (ASN1, ()) wrap a = (a, ()) unwrap :: (ASN1, ()) -> ASN1 unwrap (a, ()) = a -- | run the parse monad over a stream and returns the result and the remaining ASN1 Stream. runParseASN1State :: ParseASN1 () a -> [ASN1] -> Either String (a, [ASN1]) runParseASN1State f a = do (a', list) <- runParseASN1State_ f (map wrap a) return (a', map unwrap list) -- | run the parse monad over a stream and returns the result and the remaining ASN1 Stream. runParseASN1State_ :: Monoid e => ParseASN1 e a -> [(ASN1, e)] -> Either String (a, [(ASN1, e)]) runParseASN1State_ f a = do (r, State a' _) <- runP f (State a mempty) return (r, a') -- | run the parse monad over a stream and returns the result. -- -- If there's still some asn1 object in the state after calling f, -- an error will be raised. runParseASN1 :: ParseASN1 () a -> [ASN1] -> Either String a runParseASN1 f s = runParseASN1_ f (map wrap s) -- | run the parse monad over a stream and returns the result. -- -- If there's still some asn1 object in the state after calling f, -- an error will be raised. runParseASN1_ :: Monoid e => ParseASN1 e a -> [(ASN1, e)] -> Either String a runParseASN1_ f s = case runP f (State s mempty) of Left err -> Left err Right (o, State [] _) -> Right o Right (_, State er _) -> Left ("runParseASN1_: remaining state " ++ show (map fst er)) -- | get next element from the stream getNext :: Monoid e => ParseASN1 e ASN1 getNext = do list <- get case list of State [] _ -> throwParseError "empty" State ((h,e):l) es -> put (State l (es <> e)) >> return h -- | get many elements until there's nothing left getMany :: ParseASN1 e a -> ParseASN1 e [a] getMany getOne = do next <- hasNext if next then liftM2 (:) getOne (getMany getOne) else return [] -- | get next element from the stream maybe getNextMaybe :: Monoid e => (ASN1 -> Maybe a) -> ParseASN1 e (Maybe a) getNextMaybe f = do list <- get case list of State [] _ -> return Nothing State ((h,e):l) es -> let r = f h in do case r of Nothing -> put list Just _ -> put (State l (es <> e)) return r -- | get next container of specified type and return all its elements getNextContainer :: Monoid e => ASN1ConstructionType -> ParseASN1 e [(ASN1, e)] getNextContainer ty = do list <- get case list of State [] _ -> throwParseError "empty" State ((h,e):l) es | h == Start ty -> do let (l1, l2) = getConstructedEnd 0 (State l (es <> e)) put l2 >> return l1 | otherwise -> throwParseError "not an expected container" -- | run a function of the next elements of a container of specified type onNextContainer :: Monoid e => ASN1ConstructionType -> ParseASN1 e a -> ParseASN1 e a onNextContainer ty f = getNextContainer ty >>= either throwParseError return . runParseASN1_ f -- | just like getNextContainer, except it doesn't throw an error if the container doesn't exists. getNextContainerMaybe :: Monoid e => ASN1ConstructionType -> ParseASN1 e (Maybe [(ASN1, e)]) getNextContainerMaybe ty = do list <- get case list of State [] _ -> return Nothing State ((h,e):l) es | h == Start ty -> do let (l1, l2) = getConstructedEnd 0 (State l (es <> e)) put l2 >> return (Just l1) | otherwise -> return Nothing -- | just like onNextContainer, except it doesn't throw an error if the container doesn't exists. onNextContainerMaybe :: Monoid e => ASN1ConstructionType -> ParseASN1 e a -> ParseASN1 e (Maybe a) onNextContainerMaybe ty f = do n <- getNextContainerMaybe ty case n of Just l -> either throwParseError (return . Just) $ runParseASN1_ f l Nothing -> return Nothing -- | returns if there's more elements in the stream. hasNext :: ParseASN1 e Bool hasNext = do State l _ <- get; return . not . null $ l -- | run a parser and return its result as well as all annotations that were used withAnnotations :: Monoid e => ParseASN1 e a -> ParseASN1 e (a, e) withAnnotations f = do State l es <- get case runP f (State l mempty) of Left err -> throwParseError err Right (a, State l' es') -> do put (State l' (es <> es')) return (a, es') getConstructedEnd :: Monoid e => Int -> State e -> ([(ASN1, e)], State e) getConstructedEnd _ xs@(State [] _) = ([], xs) getConstructedEnd i (State (x@(Start _, e):xs) es) = let (yz, zs) = getConstructedEnd (i+1) (State xs (es <> e)) in (x:yz, zs) getConstructedEnd i (State (x@(End _, e):xs) es) | i == 0 = ([], State xs (es <> e)) | otherwise = let (ys, zs) = getConstructedEnd (i-1) (State xs (es <> e)) in (x:ys, zs) getConstructedEnd i (State (x@(_, e):xs) es) = let (ys, zs) = getConstructedEnd i (State xs (es <> e)) in (x:ys, zs) cryptostore-0.3.1.0/src/Crypto/Store/0000755000000000000000000000000007346545000015602 5ustar0000000000000000cryptostore-0.3.1.0/src/Crypto/Store/CMS.hs0000644000000000000000000004616407346545000016573 0ustar0000000000000000-- | -- Module : Crypto.Store.CMS -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- Cryptographic Message Syntax -- -- * : Cryptographic Message Syntax (CMS) -- * : Cryptographic Message Syntax (CMS) Algorithms -- * : Use of the RSAES-OAEP Key Transport Algorithm in the Cryptographic Message Syntax (CMS) -- * : Use of the RSASSA-PSS Signature Algorithm in Cryptographic Message Syntax (CMS) -- * : Use of the Advanced Encryption Standard (AES) Encryption Algorithm in Cryptographic Message Syntax (CMS) -- * : Use of Elliptic Curve Cryptography (ECC) Algorithms in Cryptographic Message Syntax (CMS) -- * : Using SHA2 Algorithms with Cryptographic Message Syntax -- * : Password-based Encryption for CMS -- * : Cryptographic Message Syntax (CMS) Authenticated-Enveloped-Data Content Type -- * : Using AES-CCM and AES-GCM Authenticated Encryption in the Cryptographic Message Syntax (CMS) -- * : Using Message Authentication Code (MAC) Encryption in the Cryptographic Message Syntax (CMS) -- * : Using ChaCha20-Poly1305 Authenticated Encryption in the Cryptographic Message Syntax (CMS) -- * : Use of the Elliptic Curve Diffie-Hellman Key Agreement Algorithm with X25519 and X448 in the Cryptographic Message Syntax (CMS) -- * : Use of Edwards-Curve Digital Signature Algorithm (EdDSA) Signatures in the Cryptographic Message Syntax (CMS) -- * : Use of the SHAKE One-Way Hash Functions in the Cryptographic Message Syntax (CMS) {-# LANGUAGE RecordWildCards #-} module Crypto.Store.CMS ( ContentType(..) , ContentInfo(..) , getContentType -- * Reading and writing PEM files , module Crypto.Store.CMS.PEM -- * Content encapsulation , Encap(..) , fromEncap , Encapsulates , isAttached , fromAttached , toAttachedCI , isDetached , fromDetached , toDetachedCI -- * Signed data , SignatureValue , SignatureAlg(..) , EncapsulatedContent , SignedData(..) , ProducerOfSI , ConsumerOfSI , signData , verifySignedData -- ** Signer information , SignerInfo(..) , SignerIdentifier(..) , IssuerAndSerialNumber(..) , certSigner , withPublicKey , withSignerKey , withSignerCertificate -- * Enveloped data , EncryptedKey , KeyEncryptionParams(..) , KeyTransportParams(..) , KeyAgreementParams(..) , KeyAgreementKDF(..) , RecipientInfo(..) , EnvelopedData(..) , ProducerOfRI , ConsumerOfRI , envelopData , openEnvelopedData -- ** Key Transport recipients , KTRecipientInfo(..) , RecipientIdentifier(..) , forKeyTransRecipient , withRecipientKeyTrans -- ** Key Agreement recipients , KARecipientInfo(..) , OriginatorIdentifierOrKey(..) , OriginatorPublicKey , RecipientEncryptedKey(..) , KeyAgreeRecipientIdentifier(..) , UserKeyingMaterial , forKeyAgreeRecipient , withRecipientKeyAgree -- ** Key Encryption Key recipients , KEKRecipientInfo(..) , KeyIdentifier(..) , OtherKeyAttribute(..) , KeyEncryptionKey , forKeyRecipient , withRecipientKey -- ** Password recipients , PasswordRecipientInfo(..) , forPasswordRecipient , withRecipientPassword -- * Digested data , DigestProxy(..) , DigestAlgorithm(..) , DigestedData(..) , digestData , digestVerify -- * Encrypted data , ContentEncryptionKey , ContentEncryptionCipher(..) , ContentEncryptionAlg(..) , ContentEncryptionParams , EncryptedContent , EncryptedData(..) , generateEncryptionParams , generateRC2EncryptionParams , getContentEncryptionAlg , encryptData , decryptData -- * Authenticated data , AuthenticationKey , MACAlgorithm(..) , MessageAuthenticationCode , AuthenticatedData(..) , generateAuthenticatedData , verifyAuthenticatedData -- * Authenticated-enveloped data , AuthContentEncryptionAlg(..) , AuthContentEncryptionParams , AuthEnvelopedData(..) , generateAuthEnc128Params , generateAuthEnc256Params , generateChaChaPoly1305Params , generateCCMParams , generateGCMParams , authEnvelopData , openAuthEnvelopedData -- * Key derivation , Salt , generateSalt , KeyDerivationFunc(..) , PBKDF2_PRF(..) -- * Secret-key algorithms , HasKeySize(..) , generateKey -- * RSA padding modes , MaskGenerationFunc(..) , OAEPParams(..) , PSSParams(..) -- * CMS attributes , Attribute(..) , findAttribute , setAttribute , filterAttributes -- * CMS standard attributes , getSigningTimeAttr , setSigningTimeAttr , setSigningTimeAttrCurrent -- * Originator information , OriginatorInfo(..) , CertificateChoice(..) , OtherCertificateFormat(..) , RevocationInfoChoice(..) , OtherRevocationInfoFormat(..) -- * ASN.1 representation , ASN1ObjectExact ) where import Data.ASN1.BinaryEncoding import Data.ASN1.Encoding import Data.ByteString (ByteString) import Data.Maybe (isJust) import Data.List (nub) import Crypto.Hash import Crypto.Store.ASN1.Parse import Crypto.Store.CMS.Algorithms import Crypto.Store.CMS.Attribute import Crypto.Store.CMS.Authenticated import Crypto.Store.CMS.AuthEnveloped import Crypto.Store.CMS.Digested import Crypto.Store.CMS.Encrypted import Crypto.Store.CMS.Enveloped import Crypto.Store.CMS.OriginatorInfo import Crypto.Store.CMS.Info import Crypto.Store.CMS.PEM import Crypto.Store.CMS.Signed import Crypto.Store.CMS.Type import Crypto.Store.CMS.Util import Crypto.Store.Error import Crypto.Store.Util -- DigestedData -- | Add a digested-data layer on the specified content info. digestData :: DigestAlgorithm -> ContentInfo -> DigestedData EncapsulatedContent digestData (DigestAlgorithm alg) ci = dd where dd = DigestedData { ddDigestAlgorithm = alg , ddContentType = getContentType ci , ddEncapsulatedContent = encapsulate ci , ddDigest = hash (encapsulate ci) } -- | Return the inner content info but only if the digest is valid. digestVerify :: DigestedData EncapsulatedContent -> Either StoreError ContentInfo digestVerify DigestedData{..} | not acceptable = Left (InvalidParameter "Digest too weak") | ddDigest == hash ddEncapsulatedContent = decapsulate ddContentType ddEncapsulatedContent | otherwise = Left DigestMismatch where acceptable = securityAcceptable (DigestAlgorithm ddDigestAlgorithm) -- EncryptedData -- | Add an encrypted-data layer on the specified content info. The content is -- encrypted with specified key and algorithm. -- -- Some optional attributes can be added but will not be encrypted. encryptData :: ContentEncryptionKey -> ContentEncryptionParams -> [Attribute] -> ContentInfo -> Either StoreError (EncryptedData EncryptedContent) encryptData key params attrs ci = build <$> contentEncrypt key params (encapsulate ci) where build ec = EncryptedData { edContentType = getContentType ci , edContentEncryptionParams = params , edEncryptedContent = ec , edUnprotectedAttrs = attrs } -- | Decrypt an encrypted content info using the specified key. decryptData :: ContentEncryptionKey -> EncryptedData EncryptedContent -> Either StoreError ContentInfo decryptData key EncryptedData{..} = do decrypted <- contentDecrypt key edContentEncryptionParams edEncryptedContent decapsulate edContentType decrypted -- EnvelopedData -- | Add an enveloped-data layer on the specified content info. The content is -- encrypted with specified key and algorithm. The key is then processed by -- one or several 'ProducerOfRI' functions to create recipient info elements. -- -- Some optional attributes can be added but will not be encrypted. envelopData :: Applicative f => OriginatorInfo -> ContentEncryptionKey -> ContentEncryptionParams -> [ProducerOfRI f] -> [Attribute] -> ContentInfo -> f (Either StoreError (EnvelopedData EncryptedContent)) envelopData oinfo key params envFns attrs ci = f <$> (sequence <$> traverse ($ key) envFns) where ebs = contentEncrypt key params (encapsulate ci) f ris = build <$> ebs <*> ris build bs ris = EnvelopedData { evOriginatorInfo = oinfo , evRecipientInfos = ris , evContentType = getContentType ci , evContentEncryptionParams = params , evEncryptedContent = bs , evUnprotectedAttrs = attrs } -- | Recover an enveloped content info using the specified 'ConsumerOfRI' -- function. openEnvelopedData :: Monad m => ConsumerOfRI m -> EnvelopedData EncryptedContent -> m (Either StoreError ContentInfo) openEnvelopedData devFn EnvelopedData{..} = do r <- riAttempts (map (fmap (>>= decr) . devFn) evRecipientInfos) return (r >>= decapsulate ct) where ct = evContentType params = evContentEncryptionParams decr k = contentDecrypt k params evEncryptedContent -- AuthenticatedData -- | Key used for authentication. type AuthenticationKey = ContentEncryptionKey -- | Add an authenticated-data layer on the specified content info. The content -- is MACed with the specified key and algorithms. The key is then processed by -- one or several 'ProducerOfRI' functions to create recipient info elements. -- -- Two lists of optional attributes can be provided. The attributes will be -- part of message authentication when provided in the first list. generateAuthenticatedData :: Applicative f => OriginatorInfo -> AuthenticationKey -> MACAlgorithm -> Maybe DigestAlgorithm -> [ProducerOfRI f] -> [Attribute] -> [Attribute] -> ContentInfo -> f (Either StoreError (AuthenticatedData EncapsulatedContent)) generateAuthenticatedData oinfo key macAlg digAlg envFns aAttrs uAttrs ci = f <$> (sequence <$> traverse ($ key) envFns) where msg = encapsulate ci ct = getContentType ci (aAttrs', input) = case digAlg of Nothing -> (aAttrs, msg) Just dig -> let md = digest dig msg l = setContentTypeAttr ct $ setMessageDigestAttr md aAttrs in (l, encodeAuthAttrs l) ebs = mac macAlg key input f ris = build ebs <$> ris build authTag ris = AuthenticatedData { adOriginatorInfo = oinfo , adRecipientInfos = ris , adMACAlgorithm = macAlg , adDigestAlgorithm = digAlg , adContentType = getContentType ci , adEncapsulatedContent = encapsulate ci , adAuthAttrs = aAttrs' , adMAC = authTag , adUnauthAttrs = uAttrs } -- | Verify the integrity of an authenticated content info using the specified -- 'ConsumerOfRI' function. The inner content info is returned only if the MAC -- could be verified. verifyAuthenticatedData :: Monad m => ConsumerOfRI m -> AuthenticatedData EncapsulatedContent -> m (Either StoreError ContentInfo) verifyAuthenticatedData devFn AuthenticatedData{..} = riAttempts (map (fmap (>>= unwrap) . devFn) adRecipientInfos) where msg = adEncapsulatedContent ct = adContentType noAttr = null adAuthAttrs mdMatch = case adDigestAlgorithm of Nothing -> False Just dig -> mdAttr == Just (digest dig msg) mdAccept = maybe True securityAcceptable adDigestAlgorithm macAccept = securityAcceptable adMACAlgorithm attrMatch = ctAttr == Just ct && mdMatch mdAttr = getMessageDigestAttr adAuthAttrs ctAttr = getContentTypeAttr adAuthAttrs input = if noAttr then msg else encodeAuthAttrs adAuthAttrs unwrap k | isJust adDigestAlgorithm && noAttr = Left (InvalidInput "Missing auth attributes") | not noAttr && not attrMatch = Left (InvalidInput "Invalid auth attributes") | not mdAccept = Left (InvalidParameter "Digest too weak") | not macAccept = Left (InvalidParameter "MAC too weak") | adMAC /= mac adMACAlgorithm k input = Left BadContentMAC | otherwise = decapsulate adContentType adEncapsulatedContent -- AuthEnvelopedData -- | Add an authenticated-enveloped-data layer on the specified content info. -- The content is encrypted with specified key and algorithm. The key is then -- processed by one or several 'ProducerOfRI' functions to create recipient info -- elements. -- -- Some attributes can be added but will not be encrypted. The attributes -- will be part of message authentication when provided in the first list. authEnvelopData :: Applicative f => OriginatorInfo -> ContentEncryptionKey -> AuthContentEncryptionParams -> [ProducerOfRI f] -> [Attribute] -> [Attribute] -> ContentInfo -> f (Either StoreError (AuthEnvelopedData EncryptedContent)) authEnvelopData oinfo key params envFns aAttrs uAttrs ci = f <$> (sequence <$> traverse ($ key) envFns) where raw = encodeASN1Object params aad = encodeAuthAttrs aAttrs ebs = authContentEncrypt key params raw aad (encapsulate ci) f ris = build <$> ebs <*> ris build (authTag, bs) ris = AuthEnvelopedData { aeOriginatorInfo = oinfo , aeRecipientInfos = ris , aeContentType = getContentType ci , aeContentEncryptionParams = ASN1ObjectExact params raw , aeEncryptedContent = bs , aeAuthAttrs = aAttrs , aeMAC = authTag , aeUnauthAttrs = uAttrs } -- | Recover an authenticated-enveloped content info using the specified -- 'ConsumerOfRI' function. openAuthEnvelopedData :: Monad m => ConsumerOfRI m -> AuthEnvelopedData EncryptedContent -> m (Either StoreError ContentInfo) openAuthEnvelopedData devFn AuthEnvelopedData{..} = do r <- riAttempts (map (fmap (>>= decr) . devFn) aeRecipientInfos) return (r >>= decapsulate ct) where ct = aeContentType params = exactObject aeContentEncryptionParams raw = exactObjectRaw aeContentEncryptionParams aad = encodeAuthAttrs aeAuthAttrs decr k = authContentDecrypt k params raw aad aeEncryptedContent aeMAC -- SignedData -- | Add a signed-data layer on the specified content info. The content is -- processed by one or several 'ProducerOfSI' functions to create signer info -- elements. signData :: Applicative f => [ProducerOfSI f] -> ContentInfo -> f (Either StoreError (SignedData EncapsulatedContent)) signData sigFns ci = f <$> (sequence <$> traverse (\fn -> fn ct msg) sigFns) where msg = encapsulate ci ct = getContentType ci f = fmap (build . unzip3) build (sis, certLists, crlLists) = SignedData { sdDigestAlgorithms = nub (map siDigestAlgorithm sis) , sdContentType = getContentType ci , sdEncapsulatedContent = encapsulate ci , sdCertificates = concat certLists , sdCRLs = concat crlLists , sdSignerInfos = sis } -- | Verify a signed content info using the specified 'ConsumerOfSI' function. -- Verification of at least one signer info must be successful in order to -- return the inner content info. verifySignedData :: Monad m => ConsumerOfSI m -> SignedData EncapsulatedContent -> m (Either StoreError ContentInfo) verifySignedData verFn SignedData{..} = f <$> siAttemps valid sdSignerInfos where msg = sdEncapsulatedContent ct = sdContentType valid si = verFn ct msg si sdCertificates sdCRLs f bool = if bool then decapsulate sdContentType sdEncapsulatedContent else Left SignatureNotVerified -- Utilities riAttempts :: Monad m => [m (Either StoreError b)] -> m (Either StoreError b) riAttempts [] = return (Left NoRecipientInfoFound) riAttempts [single] = single riAttempts list = loop list where loop [] = return (Left NoRecipientInfoMatched) loop (x:xs) = x >>= orTail xs orTail xs (Left _) = loop xs orTail _ success = return success siAttemps :: Monad m => (a -> m Bool) -> [a] -> m Bool siAttemps _ [] = pure False siAttemps f (x:xs) = f x >>= orTail where orTail bool = if bool then return True else siAttemps f xs decode :: ParseASN1 [ASN1Event] a -> ByteString -> Either StoreError a decode parser bs = vals >>= mapLeft ParseFailure . runParseASN1_ parser where vals = mapLeft DecodingError (decodeASN1Repr' BER bs) -- | Encode the information for encapsulation in another content info. encapsulate :: ContentInfo -> ByteString encapsulate (DataCI bs) = bs encapsulate (SignedDataCI ed) = encodeASN1Object ed encapsulate (EnvelopedDataCI ed) = encodeASN1Object ed encapsulate (DigestedDataCI dd) = encodeASN1Object dd encapsulate (EncryptedDataCI ed) = encodeASN1Object ed encapsulate (AuthenticatedDataCI ad) = encodeASN1Object ad encapsulate (AuthEnvelopedDataCI ae) = encodeASN1Object ae -- | Decode the information from encapsulated content. decapsulate :: ContentType -> ByteString -> Either StoreError ContentInfo decapsulate DataType bs = pure (DataCI bs) decapsulate SignedDataType bs = SignedDataCI <$> decode parse bs decapsulate EnvelopedDataType bs = EnvelopedDataCI <$> decode parse bs decapsulate DigestedDataType bs = DigestedDataCI <$> decode parse bs decapsulate EncryptedDataType bs = EncryptedDataCI <$> decode parse bs decapsulate AuthenticatedDataType bs = AuthenticatedDataCI <$> decode parse bs decapsulate AuthEnvelopedDataType bs = AuthEnvelopedDataCI <$> decode parse bs cryptostore-0.3.1.0/src/Crypto/Store/CMS/0000755000000000000000000000000007346545000016224 5ustar0000000000000000cryptostore-0.3.1.0/src/Crypto/Store/CMS/Algorithms.hs0000644000000000000000000027346007346545000020705 0ustar0000000000000000-- | -- Module : Crypto.Store.CMS.Algorithms -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- Cryptographic Message Syntax algorithms {-# LANGUAGE DataKinds #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeFamilies #-} module Crypto.Store.CMS.Algorithms ( DigestAlgorithm(..) , DigestProxy(..) , digest , MessageAuthenticationCode , MACAlgorithm(..) , mac , HasStrength , securityAcceptable , HasKeySize(..) , getMaximumKeySize , validateKeySize , generateKey , ContentEncryptionCipher(..) , ContentEncryptionAlg(..) , ContentEncryptionParams(..) , generateEncryptionParams , generateRC2EncryptionParams , getContentEncryptionAlg , proxyBlockSize , contentEncrypt , contentDecrypt , AuthContentEncryptionAlg(..) , AuthContentEncryptionParams , generateAuthEnc128Params , generateAuthEnc256Params , generateChaChaPoly1305Params , generateCCMParams , generateGCMParams , authContentEncrypt , authContentDecrypt , PBKDF2_PRF(..) , prf , Salt , generateSalt , KeyDerivationFunc(..) , kdfKeyLength , kdfDerive , KeyEncryptionParams(..) , keyEncrypt , keyDecrypt , OAEPParams(..) , KeyTransportParams(..) , transportEncrypt , transportDecrypt , KeyAgreementParams(..) , KeyAgreementKDF(..) , ECDHPair , ecdhGenerate , ecdhPublic , ecdhEncrypt , ecdhDecrypt , MaskGenerationFunc(..) , mgf , SignatureValue , PSSParams(..) , SignatureAlg(..) , signatureResolveHash , signatureCheckHash , signatureGenerate , signatureVerify ) where import Control.Applicative import Control.Monad (guard, when) import Data.ASN1.BinaryEncoding import Data.ASN1.OID import Data.ASN1.Encoding import Data.ASN1.Types import Data.Bits import Data.ByteArray (ByteArray, ByteArrayAccess) import qualified Data.ByteArray as B import Data.ByteString (ByteString) import Data.Maybe (fromMaybe) import Data.Proxy import Data.Word import qualified Data.X509 as X509 import Data.X509.EC import GHC.TypeLits import qualified Crypto.Cipher.AES as Cipher import qualified Crypto.Cipher.CAST5 as Cipher import qualified Crypto.Cipher.Camellia as Cipher import qualified Crypto.Cipher.ChaChaPoly1305 as ChaChaPoly1305 import qualified Crypto.Cipher.DES as Cipher import qualified Crypto.Cipher.TripleDES as Cipher import Crypto.Cipher.Types import Crypto.Data.Padding import Crypto.ECC (Curve_X25519, Curve_X448, ecdh) import Crypto.Error import qualified Crypto.Hash as Hash import qualified Crypto.KDF.HKDF as HKDF import qualified Crypto.KDF.PBKDF2 as PBKDF2 import qualified Crypto.KDF.Scrypt as Scrypt import qualified Crypto.MAC.HMAC as HMAC import qualified Crypto.MAC.KMAC as KMAC import qualified Crypto.MAC.Poly1305 as Poly1305 import Crypto.Number.Serialize import qualified Crypto.PubKey.Curve25519 as X25519 import qualified Crypto.PubKey.Curve448 as X448 import qualified Crypto.PubKey.DSA as DSA import qualified Crypto.PubKey.ECC.DH as ECDH import qualified Crypto.PubKey.ECC.ECDSA as ECDSA import qualified Crypto.PubKey.ECC.Types as ECC import qualified Crypto.PubKey.Ed25519 as Ed25519 import qualified Crypto.PubKey.Ed448 as Ed448 import qualified Crypto.PubKey.MaskGenFunction as MGF import qualified Crypto.PubKey.RSA.PSS as RSAPSS import qualified Crypto.PubKey.RSA.OAEP as RSAOAEP import qualified Crypto.PubKey.RSA.PKCS15 as RSA import Crypto.Random import Foreign.Ptr (Ptr) import Foreign.Storable import Crypto.Store.ASN1.Generate import Crypto.Store.ASN1.Parse import Crypto.Store.CMS.Util import Crypto.Store.Cipher.RC2 import Crypto.Store.Error import qualified Crypto.Store.KeyWrap.AES as AES_KW import qualified Crypto.Store.KeyWrap.TripleDES as TripleDES_KW import qualified Crypto.Store.KeyWrap.RC2 as RC2_KW import Crypto.Store.PKCS8.EC import Crypto.Store.Util -- Hash functions -- | CMS digest proxy. Acts like 'Data.Proxy.Proxy', i.e. provides a hash -- algorithm as type parameter. The GADT constructors map to known algorithms. data DigestProxy hashAlg where -- | MD2 MD2 :: DigestProxy Hash.MD2 -- | MD4 MD4 :: DigestProxy Hash.MD4 -- | MD5 MD5 :: DigestProxy Hash.MD5 -- | SHA-1 SHA1 :: DigestProxy Hash.SHA1 -- | SHA-224 SHA224 :: DigestProxy Hash.SHA224 -- | SHA-256 SHA256 :: DigestProxy Hash.SHA256 -- | SHA-384 SHA384 :: DigestProxy Hash.SHA384 -- | SHA-512 SHA512 :: DigestProxy Hash.SHA512 -- | SHAKE128 (256 bits) SHAKE128_256 :: DigestProxy (Hash.SHAKE128 256) -- | SHAKE256 (512 bits) SHAKE256_512 :: DigestProxy (Hash.SHAKE256 512) -- | SHAKE128 (variable size) SHAKE128 :: KnownNat n => Proxy n -> DigestProxy (Hash.SHAKE128 n) -- | SHAKE256 (variable size) SHAKE256 :: KnownNat n => Proxy n -> DigestProxy (Hash.SHAKE256 n) instance Show (DigestProxy hashAlg) where showsPrec _ MD2 = showString "MD2" showsPrec _ MD4 = showString "MD4" showsPrec _ MD5 = showString "MD5" showsPrec _ SHA1 = showString "SHA1" showsPrec _ SHA224 = showString "SHA224" showsPrec _ SHA256 = showString "SHA256" showsPrec _ SHA384 = showString "SHA384" showsPrec _ SHA512 = showString "SHA512" showsPrec _ SHAKE128_256 = showString "SHAKE128_256" showsPrec _ SHAKE256_512 = showString "SHAKE256_512" showsPrec d (SHAKE128 p) = showParen (d > 10) $ showString "SHAKE128 " . showNat 11 p showsPrec d (SHAKE256 p) = showParen (d > 10) $ showString "SHAKE256 " . showNat 11 p showNat :: KnownNat n => Int -> Proxy n -> ShowS showNat d n = showParen (d > 0) $ shows n . showString " :: Proxy " . shows (natVal n) deriving instance Eq (DigestProxy hashAlg) instance HasStrength (DigestProxy hashAlg) where getSecurityBits MD2 = 64 getSecurityBits MD4 = 64 getSecurityBits MD5 = 64 getSecurityBits SHA1 = 80 getSecurityBits SHA224 = 112 getSecurityBits SHA256 = 128 getSecurityBits SHA384 = 192 getSecurityBits SHA512 = 256 getSecurityBits SHAKE128_256 = 128 getSecurityBits SHAKE256_512 = 256 getSecurityBits (SHAKE128 a) = shakeSecurityBits 128 a getSecurityBits (SHAKE256 a) = shakeSecurityBits 256 a shakeSecurityBits :: KnownNat n => Int -> proxy n -> Int shakeSecurityBits m a = min m (fromInteger (natVal a) `div` 2) -- | CMS digest algorithm. data DigestAlgorithm = forall hashAlg . Hash.HashAlgorithm hashAlg => DigestAlgorithm (DigestProxy hashAlg) instance Show DigestAlgorithm where show (DigestAlgorithm a) = show a instance Eq DigestAlgorithm where DigestAlgorithm MD2 == DigestAlgorithm MD2 = True DigestAlgorithm MD4 == DigestAlgorithm MD4 = True DigestAlgorithm MD5 == DigestAlgorithm MD5 = True DigestAlgorithm SHA1 == DigestAlgorithm SHA1 = True DigestAlgorithm SHA224 == DigestAlgorithm SHA224 = True DigestAlgorithm SHA256 == DigestAlgorithm SHA256 = True DigestAlgorithm SHA384 == DigestAlgorithm SHA384 = True DigestAlgorithm SHA512 == DigestAlgorithm SHA512 = True DigestAlgorithm SHAKE128_256 == DigestAlgorithm SHAKE128_256 = True DigestAlgorithm SHAKE256_512 == DigestAlgorithm SHAKE256_512 = True DigestAlgorithm (SHAKE128 a) == DigestAlgorithm (SHAKE128 b) = natVal a == natVal b DigestAlgorithm (SHAKE256 a) == DigestAlgorithm (SHAKE256 b) = natVal a == natVal b _ == _ = False instance HasStrength DigestAlgorithm where getSecurityBits (DigestAlgorithm a) = getSecurityBits a data DigestType = Type_MD2 | Type_MD4 | Type_MD5 | Type_SHA1 | Type_SHA224 | Type_SHA256 | Type_SHA384 | Type_SHA512 | Type_SHAKE128_256 | Type_SHAKE256_512 | Type_SHAKE128_Len | Type_SHAKE256_Len instance Enumerable DigestType where values = [ Type_MD2 , Type_MD4 , Type_MD5 , Type_SHA1 , Type_SHA224 , Type_SHA256 , Type_SHA384 , Type_SHA512 , Type_SHAKE128_256 , Type_SHAKE256_512 , Type_SHAKE128_Len , Type_SHAKE256_Len ] instance OIDable DigestType where getObjectID Type_MD2 = [1,2,840,113549,2,2] getObjectID Type_MD4 = [1,2,840,113549,2,4] getObjectID Type_MD5 = [1,2,840,113549,2,5] getObjectID Type_SHA1 = [1,3,14,3,2,26] getObjectID Type_SHA224 = [2,16,840,1,101,3,4,2,4] getObjectID Type_SHA256 = [2,16,840,1,101,3,4,2,1] getObjectID Type_SHA384 = [2,16,840,1,101,3,4,2,2] getObjectID Type_SHA512 = [2,16,840,1,101,3,4,2,3] getObjectID Type_SHAKE128_256 = [2,16,840,1,101,3,4,2,11] getObjectID Type_SHAKE256_512 = [2,16,840,1,101,3,4,2,12] getObjectID Type_SHAKE128_Len = [2,16,840,1,101,3,4,2,17] getObjectID Type_SHAKE256_Len = [2,16,840,1,101,3,4,2,18] instance OIDNameable DigestType where fromObjectID oid = unOIDNW <$> fromObjectID oid instance AlgorithmId DigestAlgorithm where type AlgorithmType DigestAlgorithm = DigestType algorithmName _ = "digest algorithm" algorithmType (DigestAlgorithm MD2) = Type_MD2 algorithmType (DigestAlgorithm MD4) = Type_MD4 algorithmType (DigestAlgorithm MD5) = Type_MD5 algorithmType (DigestAlgorithm SHA1) = Type_SHA1 algorithmType (DigestAlgorithm SHA224) = Type_SHA224 algorithmType (DigestAlgorithm SHA256) = Type_SHA256 algorithmType (DigestAlgorithm SHA384) = Type_SHA384 algorithmType (DigestAlgorithm SHA512) = Type_SHA512 algorithmType (DigestAlgorithm SHAKE128_256) = Type_SHAKE128_256 algorithmType (DigestAlgorithm SHAKE256_512) = Type_SHAKE256_512 algorithmType (DigestAlgorithm (SHAKE128 _)) = Type_SHAKE128_Len algorithmType (DigestAlgorithm (SHAKE256 _)) = Type_SHAKE256_Len -- MD5 has NULL parameter, SHAKE128 and SHAKE256 have the bitsize as -- parameter, other algorithms have no parameter parameterASN1S (DigestAlgorithm MD5) = gNull parameterASN1S (DigestAlgorithm (SHAKE128 n)) = gIntVal (natVal n) parameterASN1S (DigestAlgorithm (SHAKE256 n)) = gIntVal (natVal n) parameterASN1S _ = id parseParameter Type_MD2 = parseDigestParam (DigestAlgorithm MD2) parseParameter Type_MD4 = parseDigestParam (DigestAlgorithm MD4) parseParameter Type_MD5 = parseDigestParam (DigestAlgorithm MD5) parseParameter Type_SHA1 = parseDigestParam (DigestAlgorithm SHA1) parseParameter Type_SHA224 = parseDigestParam (DigestAlgorithm SHA224) parseParameter Type_SHA256 = parseDigestParam (DigestAlgorithm SHA256) parseParameter Type_SHA384 = parseDigestParam (DigestAlgorithm SHA384) parseParameter Type_SHA512 = parseDigestParam (DigestAlgorithm SHA512) parseParameter Type_SHAKE128_256 = parseDigestParam (DigestAlgorithm SHAKE128_256) parseParameter Type_SHAKE256_512 = parseDigestParam (DigestAlgorithm SHAKE256_512) parseParameter Type_SHAKE128_Len = parseBitLen $ \(SomeNat p) -> return $ DigestAlgorithm (SHAKE128 p) parseParameter Type_SHAKE256_Len = parseBitLen $ \(SomeNat p) -> return $ DigestAlgorithm (SHAKE256 p) -- | Compute the digest of a message. digest :: ByteArrayAccess message => DigestAlgorithm -> message -> ByteString digest (DigestAlgorithm hashAlg) message = B.convert (doHash hashAlg message) doHash :: (Hash.HashAlgorithm hashAlg, ByteArrayAccess ba) => proxy hashAlg -> ba -> Hash.Digest hashAlg doHash _ = Hash.hash hashFromProxy :: proxy a -> a hashFromProxy _ = undefined parseDigestParam :: Monoid e => DigestAlgorithm -> ParseASN1 e DigestAlgorithm parseDigestParam p = getNextMaybe nullOrNothing >> return p parseBitLen :: Monoid e => (SomeNat -> ParseASN1 e a) -> ParseASN1 e a parseBitLen fn = do IntVal n <- getNext case someNatVal n of Nothing -> throwParseError ("Invalid bit length: " ++ show n) Just sn -> fn sn p256 :: Proxy 256 p256 = Proxy p512 :: Proxy 512 p512 = Proxy -- Security strength -- | Algorithms with known security strength. class HasStrength params where -- | Get security strength in bits. -- -- This returns the strength for which the algorithm was designed. -- Algorithms with weaknesses have an effective strength lower than the -- returned value. getSecurityBits :: params -> Int -- | Whether the algorithm has acceptable security. The goal is to eliminate -- variable-length algorithms, like SHAKE with 1-byte output, that would make -- strength lower than the weakest fixed-length algorithm. securityAcceptable :: HasStrength params => params -> Bool securityAcceptable = (>= 64) . getSecurityBits -- Cipher-like things -- | Algorithms that are based on a secret key. This includes ciphers but also -- MAC algorithms. class HasKeySize params where -- | Get a specification of the key sizes allowed by the algorithm. getKeySizeSpecifier :: params -> KeySizeSpecifier -- | Return the maximum key size for the specified algorithm. getMaximumKeySize :: HasKeySize params => params -> Int getMaximumKeySize params = case getKeySizeSpecifier params of KeySizeRange _ n -> n KeySizeEnum l -> maximum l KeySizeFixed n -> n -- | Return 'True' if the specified key size is valid for the specified -- algorithm. validateKeySize :: HasKeySize params => params -> Int -> Bool validateKeySize params len = case getKeySizeSpecifier params of KeySizeRange a b -> a <= len && len <= b KeySizeEnum l -> len `elem` l KeySizeFixed n -> len == n -- | Generate a random key suitable for the specified algorithm. This uses the -- maximum size allowed by the parameters. generateKey :: (HasKeySize params, MonadRandom m, ByteArray key) => params -> m key generateKey params = getRandomBytes (getMaximumKeySize params) -- MAC -- | Message authentication code. Equality is time constant. type MessageAuthenticationCode = AuthTag data MACType = forall hashAlg . Hash.HashAlgorithm hashAlg => TypeHMAC (DigestProxy hashAlg) | TypeKMAC_SHAKE128 | TypeKMAC_SHAKE256 deriving instance Show MACType -- | Message Authentication Code (MAC) Algorithm. data MACAlgorithm = forall hashAlg . Hash.HashAlgorithm hashAlg => HMAC (DigestProxy hashAlg) | forall n . KnownNat n => KMAC_SHAKE128 (Proxy n) ByteString | forall n . KnownNat n => KMAC_SHAKE256 (Proxy n) ByteString instance Show MACAlgorithm where showsPrec d (HMAC p) = showParen (d > 10) $ showString "HMAC " . showsPrec 11 p showsPrec d (KMAC_SHAKE128 p s) = showParen (d > 10) $ showString "KMAC_SHAKE128 " . showNat 11 p . showChar ' ' . showsPrec 11 s showsPrec d (KMAC_SHAKE256 p s) = showParen (d > 10) $ showString "KMAC_SHAKE256 " . showNat 11 p . showChar ' ' . showsPrec 11 s instance Eq MACAlgorithm where HMAC a1 == HMAC a2 = DigestAlgorithm a1 == DigestAlgorithm a2 KMAC_SHAKE128 p1 s1 == KMAC_SHAKE128 p2 s2 = natVal p1 == natVal p2 && s1 == s2 KMAC_SHAKE256 p1 s1 == KMAC_SHAKE256 p2 s2 = natVal p1 == natVal p2 && s1 == s2 _ == _ = False instance HasStrength MACAlgorithm where getSecurityBits (HMAC a) = getSecurityBits (DigestAlgorithm a) getSecurityBits (KMAC_SHAKE128 p _) = shakeSecurityBits 128 p getSecurityBits (KMAC_SHAKE256 p _) = shakeSecurityBits 256 p instance Enumerable MACType where values = [ TypeHMAC MD5 , TypeHMAC SHA1 , TypeHMAC SHA224 , TypeHMAC SHA256 , TypeHMAC SHA384 , TypeHMAC SHA512 , TypeKMAC_SHAKE128 , TypeKMAC_SHAKE256 ] instance OIDable MACType where getObjectID (TypeHMAC MD5) = [1,3,6,1,5,5,8,1,1] getObjectID (TypeHMAC SHA1) = [1,3,6,1,5,5,8,1,2] getObjectID (TypeHMAC SHA224) = [1,2,840,113549,2,8] getObjectID (TypeHMAC SHA256) = [1,2,840,113549,2,9] getObjectID (TypeHMAC SHA384) = [1,2,840,113549,2,10] getObjectID (TypeHMAC SHA512) = [1,2,840,113549,2,11] getObjectID TypeKMAC_SHAKE128 = [2,16,840,1,101,3,4,2,19] getObjectID TypeKMAC_SHAKE256 = [2,16,840,1,101,3,4,2,20] getObjectID ty = error ("Unsupported MACAlgorithm: " ++ show ty) instance OIDNameable MACType where fromObjectID oid = unOIDNW <$> fromObjectID oid instance AlgorithmId MACAlgorithm where type AlgorithmType MACAlgorithm = MACType algorithmName _ = "mac algorithm" algorithmType (HMAC alg) = TypeHMAC alg algorithmType (KMAC_SHAKE128 _ _) = TypeKMAC_SHAKE128 algorithmType (KMAC_SHAKE256 _ _) = TypeKMAC_SHAKE256 parameterASN1S (HMAC _) = id parameterASN1S (KMAC_SHAKE128 p str) = kmacASN1S 256 p str parameterASN1S (KMAC_SHAKE256 p str) = kmacASN1S 512 p str parseParameter (TypeHMAC alg) = getNextMaybe nullOrNothing >> return (HMAC alg) parseParameter TypeKMAC_SHAKE128 = parseKMAC p256 KMAC_SHAKE128 parseParameter TypeKMAC_SHAKE256 = parseKMAC p512 KMAC_SHAKE256 kmacASN1S :: (KnownNat n, ASN1Elem e) => Integer -> proxy n -> ByteString -> ASN1Stream e kmacASN1S n p str | B.null str && n == i = id | otherwise = asn1Container Sequence (gIntVal i . gOctetString str) where i = natVal p parseKMAC :: (Monoid e, KnownNat n') => Proxy n' -> (forall n . KnownNat n => Proxy n -> ByteString -> MACAlgorithm) -> ParseASN1 e MACAlgorithm parseKMAC p' fn = do b <- hasNext if b then parseParams else return (fn p' B.empty) where parseParams = onNextContainer Sequence $ parseBitLen $ \(SomeNat p) -> getNext >>= \(OctetString str) -> return (fn p str) instance HasKeySize MACAlgorithm where getKeySizeSpecifier (HMAC a) = KeySizeFixed (digestSizeFromProxy a) getKeySizeSpecifier (KMAC_SHAKE128 p _) = KeySizeFixed (digestSizeFromProxy (SHAKE128 p)) getKeySizeSpecifier (KMAC_SHAKE256 p _) = KeySizeFixed (digestSizeFromProxy (SHAKE256 p)) digestSizeFromProxy :: Hash.HashAlgorithm a => proxy a -> Int digestSizeFromProxy = Hash.hashDigestSize . hashFromProxy -- | Invoke the MAC function. mac :: (ByteArrayAccess key, ByteArrayAccess message) => MACAlgorithm -> key -> message -> MessageAuthenticationCode mac (HMAC alg) = hmacWith alg where hmacWith p key = AuthTag . B.convert . runHMAC p key runHMAC :: (Hash.HashAlgorithm a, ByteArrayAccess k, ByteArrayAccess m) => proxy a -> k -> m -> HMAC.HMAC a runHMAC _ = HMAC.hmac mac (KMAC_SHAKE128 p str) = \key -> AuthTag . B.convert . run128 p str key where run128 :: (KnownNat n, ByteArrayAccess k, ByteArrayAccess m) => proxy n -> ByteString -> k -> m -> KMAC.KMAC (Hash.SHAKE128 n) run128 _ = KMAC.kmac mac (KMAC_SHAKE256 p str) = \key -> AuthTag . B.convert . run256 p str key where run256 :: (KnownNat n, ByteArrayAccess k, ByteArrayAccess m) => proxy n -> ByteString -> k -> m -> KMAC.KMAC (Hash.SHAKE256 n) run256 _ = KMAC.kmac -- Content encryption -- | CMS content encryption cipher. data ContentEncryptionCipher cipher where -- | DES DES :: ContentEncryptionCipher Cipher.DES -- | Triple-DES with 2 keys used in alternative direction DES_EDE2 :: ContentEncryptionCipher Cipher.DES_EDE2 -- | Triple-DES with 3 keys used in alternative direction DES_EDE3 :: ContentEncryptionCipher Cipher.DES_EDE3 -- | AES with 128-bit key AES128 :: ContentEncryptionCipher Cipher.AES128 -- | AES with 192-bit key AES192 :: ContentEncryptionCipher Cipher.AES192 -- | AES with 256-bit key AES256 :: ContentEncryptionCipher Cipher.AES256 -- | CAST5 (aka CAST-128) with key between 40 and 128 bits CAST5 :: ContentEncryptionCipher Cipher.CAST5 -- | Camellia with 128-bit key Camellia128 :: ContentEncryptionCipher Cipher.Camellia128 deriving instance Show (ContentEncryptionCipher cipher) deriving instance Eq (ContentEncryptionCipher cipher) cecI :: ContentEncryptionCipher c -> Int cecI DES = 0 cecI DES_EDE2 = 1 cecI DES_EDE3 = 2 cecI AES128 = 3 cecI AES192 = 4 cecI AES256 = 5 cecI CAST5 = 6 cecI Camellia128 = 7 getCipherKeySizeSpecifier :: Cipher cipher => proxy cipher -> KeySizeSpecifier getCipherKeySizeSpecifier = cipherKeySize . cipherFromProxy -- | Cipher and mode of operation for content encryption. data ContentEncryptionAlg = forall c . BlockCipher c => ECB (ContentEncryptionCipher c) -- ^ Electronic Codebook | forall c . BlockCipher c => CBC (ContentEncryptionCipher c) -- ^ Cipher Block Chaining | CBC_RC2 -- ^ RC2 in CBC mode | forall c . BlockCipher c => CFB (ContentEncryptionCipher c) -- ^ Cipher Feedback | forall c . BlockCipher c => CTR (ContentEncryptionCipher c) -- ^ Counter instance Show ContentEncryptionAlg where show (ECB c) = shows c "_ECB" show (CBC c) = shows c "_CBC" show CBC_RC2 = "RC2_CBC" show (CFB c) = shows c "_CFB" show (CTR c) = shows c "_CTR" instance Enumerable ContentEncryptionAlg where values = [ CBC DES , CBC DES_EDE3 , CBC AES128 , CBC AES192 , CBC AES256 , CBC CAST5 , CBC Camellia128 , CBC_RC2 , ECB DES , ECB AES128 , ECB AES192 , ECB AES256 , ECB Camellia128 , CFB DES , CFB AES128 , CFB AES192 , CFB AES256 , CFB Camellia128 , CTR Camellia128 ] instance OIDable ContentEncryptionAlg where getObjectID (CBC DES) = [1,3,14,3,2,7] getObjectID (CBC DES_EDE3) = [1,2,840,113549,3,7] getObjectID (CBC AES128) = [2,16,840,1,101,3,4,1,2] getObjectID (CBC AES192) = [2,16,840,1,101,3,4,1,22] getObjectID (CBC AES256) = [2,16,840,1,101,3,4,1,42] getObjectID (CBC CAST5) = [1,2,840,113533,7,66,10] getObjectID (CBC Camellia128) = [1,2,392,200011,61,1,1,1,2] getObjectID CBC_RC2 = [1,2,840,113549,3,2] getObjectID (ECB DES) = [1,3,14,3,2,6] getObjectID (ECB AES128) = [2,16,840,1,101,3,4,1,1] getObjectID (ECB AES192) = [2,16,840,1,101,3,4,1,21] getObjectID (ECB AES256) = [2,16,840,1,101,3,4,1,41] getObjectID (ECB Camellia128) = [0,3,4401,5,3,1,9,1] getObjectID (CFB DES) = [1,3,14,3,2,9] getObjectID (CFB AES128) = [2,16,840,1,101,3,4,1,4] getObjectID (CFB AES192) = [2,16,840,1,101,3,4,1,24] getObjectID (CFB AES256) = [2,16,840,1,101,3,4,1,44] getObjectID (CFB Camellia128) = [0,3,4401,5,3,1,9,4] getObjectID (CTR Camellia128) = [0,3,4401,5,3,1,9,9] getObjectID ty = error ("Unsupported ContentEncryptionAlg: " ++ show ty) instance OIDNameable ContentEncryptionAlg where fromObjectID oid = unOIDNW <$> fromObjectID oid -- | Content encryption algorithm with associated parameters (i.e. the -- initialization vector). -- -- A value can be generated with 'generateEncryptionParams'. data ContentEncryptionParams = forall c . BlockCipher c => ParamsECB (ContentEncryptionCipher c) -- ^ Electronic Codebook | forall c . BlockCipher c => ParamsCBC (ContentEncryptionCipher c) (IV c) -- ^ Cipher Block Chaining | ParamsCBCRC2 Int (IV RC2) -- ^ RC2 in CBC mode | forall c . BlockCipher c => ParamsCFB (ContentEncryptionCipher c) (IV c) -- ^ Cipher Feedback | forall c . BlockCipher c => ParamsCTR (ContentEncryptionCipher c) (IV c) -- ^ Counter instance Show ContentEncryptionParams where show = show . getContentEncryptionAlg instance Eq ContentEncryptionParams where ParamsECB c1 == ParamsECB c2 = cecI c1 == cecI c2 ParamsCBC c1 iv1 == ParamsCBC c2 iv2 = cecI c1 == cecI c2 && iv1 `B.eq` iv2 ParamsCBCRC2 i1 iv1 == ParamsCBCRC2 i2 iv2 = i1 == i2 && iv1 `B.eq` iv2 ParamsCFB c1 iv1 == ParamsCFB c2 iv2 = cecI c1 == cecI c2 && iv1 `B.eq` iv2 ParamsCTR c1 iv1 == ParamsCTR c2 iv2 = cecI c1 == cecI c2 && iv1 `B.eq` iv2 _ == _ = False instance HasKeySize ContentEncryptionParams where getKeySizeSpecifier (ParamsECB c) = getCipherKeySizeSpecifier c getKeySizeSpecifier (ParamsCBC c _) = getCipherKeySizeSpecifier c getKeySizeSpecifier (ParamsCBCRC2 i _) = KeySizeFixed $ (i + 7) `div` 8 getKeySizeSpecifier (ParamsCFB c _) = getCipherKeySizeSpecifier c getKeySizeSpecifier (ParamsCTR c _) = getCipherKeySizeSpecifier c instance ASN1Elem e => ProduceASN1Object e ContentEncryptionParams where asn1s param = asn1Container Sequence (oid . params) where oid = gOID (getObjectID $ getContentEncryptionAlg param) params = ceParameterASN1S param instance Monoid e => ParseASN1Object e ContentEncryptionParams where parse = onNextContainer Sequence $ do OID oid <- getNext withObjectID "content encryption algorithm" oid parseCEParameter ceParameterASN1S :: ASN1Elem e => ContentEncryptionParams -> ASN1Stream e ceParameterASN1S (ParamsECB _) = id ceParameterASN1S (ParamsCBC _ iv) = gOctetString (B.convert iv) ceParameterASN1S (ParamsCBCRC2 len iv) = rc2ParameterASN1S len iv ceParameterASN1S (ParamsCFB _ iv) = gOctetString (B.convert iv) ceParameterASN1S (ParamsCTR _ iv) = gOctetString (B.convert iv) parseCEParameter :: Monoid e => ContentEncryptionAlg -> ParseASN1 e ContentEncryptionParams parseCEParameter (ECB c) = getMany getNext >> return (ParamsECB c) parseCEParameter (CBC c) = ParamsCBC c <$> (getNext >>= getIV) parseCEParameter CBC_RC2 = parseRC2Parameter parseCEParameter (CFB c) = ParamsCFB c <$> (getNext >>= getIV) parseCEParameter (CTR c) = ParamsCTR c <$> (getNext >>= getIV) getIV :: BlockCipher cipher => ASN1 -> ParseASN1 e (IV cipher) getIV (OctetString ivBs) = case makeIV ivBs of Nothing -> throwParseError "Bad IV in parsed parameters" Just v -> return v getIV _ = throwParseError "No IV in parsed parameter or incorrect format" rc2ParameterASN1S :: ASN1Elem e => Int -> IV RC2 -> ASN1Stream e rc2ParameterASN1S len iv | len == 32 = gIV | otherwise = asn1Container Sequence (rc2VersionASN1 len . gIV) where gIV = gOctetString (B.convert iv) parseRC2Parameter :: Monoid e => ParseASN1 e ContentEncryptionParams parseRC2Parameter = parseOnlyIV 32 <|> parseFullParams where parseOnlyIV len = ParamsCBCRC2 len <$> (getNext >>= getIV) parseFullParams = onNextContainer Sequence $ parseRC2Version >>= parseOnlyIV -- | Get the content encryption algorithm. getContentEncryptionAlg :: ContentEncryptionParams -> ContentEncryptionAlg getContentEncryptionAlg (ParamsECB c) = ECB c getContentEncryptionAlg (ParamsCBC c _) = CBC c getContentEncryptionAlg (ParamsCBCRC2 _ _) = CBC_RC2 getContentEncryptionAlg (ParamsCFB c _) = CFB c getContentEncryptionAlg (ParamsCTR c _) = CTR c -- | Generate random parameters for the specified content encryption algorithm. generateEncryptionParams :: MonadRandom m => ContentEncryptionAlg -> m ContentEncryptionParams generateEncryptionParams (ECB c) = return (ParamsECB c) generateEncryptionParams (CBC c) = ParamsCBC c <$> ivGenerate undefined generateEncryptionParams CBC_RC2 = ParamsCBCRC2 128 <$> ivGenerate undefined generateEncryptionParams (CFB c) = ParamsCFB c <$> ivGenerate undefined generateEncryptionParams (CTR c) = ParamsCTR c <$> ivGenerate undefined -- | Generate random RC2 parameters with the specified effective key length (in -- bits). generateRC2EncryptionParams :: MonadRandom m => Int -> m ContentEncryptionParams generateRC2EncryptionParams len = ParamsCBCRC2 len <$> ivGenerate undefined -- | Encrypt a bytearray with the specified content encryption key and -- algorithm. contentEncrypt :: (ByteArray cek, ByteArray ba) => cek -> ContentEncryptionParams -> ba -> Either StoreError ba contentEncrypt key params bs = case params of ParamsECB cipher -> getCipher cipher key >>= (\c -> force $ ecbEncrypt c $ padded c bs) ParamsCBC cipher iv -> getCipher cipher key >>= (\c -> force $ cbcEncrypt c iv $ padded c bs) ParamsCBCRC2 len iv -> getRC2Cipher len key >>= (\c -> force $ cbcEncrypt c iv $ padded c bs) ParamsCFB cipher iv -> getCipher cipher key >>= (\c -> force $ cfbEncrypt c iv $ padded c bs) ParamsCTR cipher iv -> getCipher cipher key >>= (\c -> force $ ctrCombine c iv $ padded c bs) where force x = x `seq` Right x padded c = pad (PKCS7 $ blockSize c) -- | Decrypt a bytearray with the specified content encryption key and -- algorithm. contentDecrypt :: (ByteArray cek, ByteArray ba) => cek -> ContentEncryptionParams -> ba -> Either StoreError ba contentDecrypt key params bs = case params of ParamsECB cipher -> getCipher cipher key >>= (\c -> unpadded c (ecbDecrypt c bs)) ParamsCBC cipher iv -> getCipher cipher key >>= (\c -> unpadded c (cbcDecrypt c iv bs)) ParamsCBCRC2 len iv -> getRC2Cipher len key >>= (\c -> unpadded c (cbcDecrypt c iv bs)) ParamsCFB cipher iv -> getCipher cipher key >>= (\c -> unpadded c (cfbDecrypt c iv bs)) ParamsCTR cipher iv -> getCipher cipher key >>= (\c -> unpadded c (ctrCombine c iv bs)) where unpadded c decrypted = case unpad (PKCS7 $ blockSize c) decrypted of Nothing -> Left DecryptionFailed Just out -> Right out -- from RFC 2268 section 6 rc2Table :: [Word8] rc2Table = [ 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0 , 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a , 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36 , 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c , 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60 , 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa , 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e , 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf , 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6 , 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3 , 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c , 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2 , 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5 , 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5 , 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f , 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab ] rc2Forward :: B.Bytes rc2Forward = B.pack rc2Table rc2Reverse :: B.Bytes rc2Reverse = B.allocAndFreeze (length rc2Table) (loop $ zip [0..] rc2Table) where loop :: [(Word8, Word8)] -> Ptr Word8 -> IO () loop [] _ = return () loop ((a,b):ts) p = pokeElemOff p (fromIntegral b) a >> loop ts p rc2VersionASN1 :: ASN1Elem e => Int -> ASN1Stream e rc2VersionASN1 len = gIntVal v where v | len < 0 = error "invalid RC2 effective key length" | len >= 256 = fromIntegral len | otherwise = fromIntegral (B.index rc2Forward len) parseRC2Version :: Monoid e => ParseASN1 e Int parseRC2Version = do IntVal i <- getNext when (i < 0) $ throwParseError "Parsed invalid RC2 effective key length" let j = fromIntegral i return $ if i >= 256 then j else fromIntegral (B.index rc2Reverse j) -- Authenticated-content encryption -- | Cipher and mode of operation for authenticated-content encryption. data AuthContentEncryptionAlg = AUTH_ENC_128 -- ^ authEnc with 128-bit key | AUTH_ENC_256 -- ^ authEnc with 256-bit key | CHACHA20_POLY1305 -- ^ ChaCha20-Poly1305 Authenticated Encryption | forall c . BlockCipher c => CCM (ContentEncryptionCipher c) -- ^ Counter with CBC-MAC | forall c . BlockCipher c => GCM (ContentEncryptionCipher c) -- ^ Galois Counter Mode instance Show AuthContentEncryptionAlg where show AUTH_ENC_128 = "AUTH_ENC_128" show AUTH_ENC_256 = "AUTH_ENC_256" show CHACHA20_POLY1305 = "CHACHA20_POLY1305" show (CCM c) = shows c "_CCM" show (GCM c) = shows c "_GCM" instance Enumerable AuthContentEncryptionAlg where values = [ AUTH_ENC_128 , AUTH_ENC_256 , CHACHA20_POLY1305 , CCM AES128 , CCM AES192 , CCM AES256 , GCM AES128 , GCM AES192 , GCM AES256 ] instance OIDable AuthContentEncryptionAlg where getObjectID AUTH_ENC_128 = [1,2,840,113549,1,9,16,3,15] getObjectID AUTH_ENC_256 = [1,2,840,113549,1,9,16,3,16] getObjectID CHACHA20_POLY1305 = [1,2,840,113549,1,9,16,3,18] getObjectID (CCM AES128) = [2,16,840,1,101,3,4,1,7] getObjectID (CCM AES192) = [2,16,840,1,101,3,4,1,27] getObjectID (CCM AES256) = [2,16,840,1,101,3,4,1,47] getObjectID (GCM AES128) = [2,16,840,1,101,3,4,1,6] getObjectID (GCM AES192) = [2,16,840,1,101,3,4,1,26] getObjectID (GCM AES256) = [2,16,840,1,101,3,4,1,46] getObjectID ty = error ("Unsupported AuthContentEncryptionAlg: " ++ show ty) instance OIDNameable AuthContentEncryptionAlg where fromObjectID oid = unOIDNW <$> fromObjectID oid data AuthEncParams = AuthEncParams { prfAlgorithm :: PBKDF2_PRF , encAlgorithm :: ContentEncryptionParams , macAlgorithm :: MACAlgorithm } deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e AuthEncParams where asn1s AuthEncParams{..} = asn1Container Sequence (kdf . encAlg . macAlg) where kdf = algorithmASN1S (Container Context 0) (asKDF prfAlgorithm) encAlg = asn1s encAlgorithm macAlg = algorithmASN1S Sequence macAlgorithm asKDF algPrf = PBKDF2 { pbkdf2Salt = B.empty , pbkdf2IterationCount = 1 , pbkdf2KeyLength = Nothing , pbkdf2Prf = algPrf } instance Monoid e => ParseASN1Object e AuthEncParams where parse = onNextContainer Sequence $ do kdf <- parseAlgorithmMaybe (Container Context 0) encAlg <- parse macAlg <- parseAlgorithm Sequence prfAlg <- case kdf of Nothing -> return PBKDF2_SHA1 Just (PBKDF2 _ _ _ a) -> return a Just other -> throwParseError ("Unable to use " ++ show other ++ " in AuthEncParams") return AuthEncParams { prfAlgorithm = prfAlg , encAlgorithm = encAlg , macAlgorithm = macAlg } -- | Authenticated-content encryption algorithm with associated parameters -- (i.e. the nonce). -- -- A value can be generated with functions 'generateAuthEnc128Params', -- 'generateAuthEnc256Params', 'generateChaChaPoly1305Params', -- 'generateCCMParams' and 'generateGCMParams'. data AuthContentEncryptionParams = Params_AUTH_ENC_128 AuthEncParams -- ^ authEnc with 128-bit keying material | Params_AUTH_ENC_256 AuthEncParams -- ^ authEnc with 256-bit keying material | Params_CHACHA20_POLY1305 ChaChaPoly1305.Nonce -- ^ ChaCha20-Poly1305 Authenticated Encryption | forall c . BlockCipher c => ParamsCCM (ContentEncryptionCipher c) B.Bytes CCM_M CCM_L -- ^ Counter with CBC-MAC | forall c . BlockCipher c => ParamsGCM (ContentEncryptionCipher c) B.Bytes Int -- ^ Galois Counter Mode instance Show AuthContentEncryptionParams where show = show . getAuthContentEncryptionAlg instance Eq AuthContentEncryptionParams where Params_AUTH_ENC_128 p1 == Params_AUTH_ENC_128 p2 = p1 == p2 Params_AUTH_ENC_256 p1 == Params_AUTH_ENC_256 p2 = p1 == p2 Params_CHACHA20_POLY1305 iv1 == Params_CHACHA20_POLY1305 iv2 = iv1 `B.eq` iv2 ParamsCCM c1 iv1 m1 l1 == ParamsCCM c2 iv2 m2 l2 = cecI c1 == cecI c2 && iv1 == iv2 && (m1, l1) == (m2, l2) ParamsGCM c1 iv1 len1 == ParamsGCM c2 iv2 len2 = cecI c1 == cecI c2 && iv1 == iv2 && len1 == len2 _ == _ = False instance HasKeySize AuthContentEncryptionParams where getKeySizeSpecifier (Params_AUTH_ENC_128 _) = KeySizeFixed 16 getKeySizeSpecifier (Params_AUTH_ENC_256 _) = KeySizeFixed 32 getKeySizeSpecifier (Params_CHACHA20_POLY1305 _) = KeySizeFixed 32 getKeySizeSpecifier (ParamsCCM c _ _ _) = getCipherKeySizeSpecifier c getKeySizeSpecifier (ParamsGCM c _ _) = getCipherKeySizeSpecifier c instance ASN1Elem e => ProduceASN1Object e AuthContentEncryptionParams where asn1s param = asn1Container Sequence (oid . params) where oid = gOID (getObjectID $ getAuthContentEncryptionAlg param) params = aceParameterASN1S param instance Monoid e => ParseASN1Object e AuthContentEncryptionParams where parse = onNextContainer Sequence $ do OID oid <- getNext withObjectID "authenticated-content encryption algorithm" oid parseACEParameter aceParameterASN1S :: ASN1Elem e => AuthContentEncryptionParams -> ASN1Stream e aceParameterASN1S (Params_AUTH_ENC_128 p) = asn1s p aceParameterASN1S (Params_AUTH_ENC_256 p) = asn1s p aceParameterASN1S (Params_CHACHA20_POLY1305 iv) = gOctetString (B.convert iv) aceParameterASN1S (ParamsCCM _ iv m _) = asn1Container Sequence (nonce . icvlen) where nonce = gOctetString (B.convert iv) icvlen = gIntVal (fromIntegral $ getM m) aceParameterASN1S (ParamsGCM _ iv len) = asn1Container Sequence (nonce . icvlen) where nonce = gOctetString (B.convert iv) icvlen = gIntVal (fromIntegral len) parseACEParameter :: Monoid e => AuthContentEncryptionAlg -> ParseASN1 e AuthContentEncryptionParams parseACEParameter AUTH_ENC_128 = Params_AUTH_ENC_128 <$> parse parseACEParameter AUTH_ENC_256 = Params_AUTH_ENC_256 <$> parse parseACEParameter CHACHA20_POLY1305 = do OctetString bs <- getNext case ChaChaPoly1305.nonce12 bs of CryptoPassed iv -> return (Params_CHACHA20_POLY1305 iv) CryptoFailed e -> throwParseError $ "Parsed invalid ChaChaPoly1305 nonce: " ++ show e parseACEParameter (CCM c) = onNextContainer Sequence $ do OctetString iv <- getNext let ivlen = B.length iv when (ivlen < 7 || ivlen > 13) $ throwParseError $ "Parsed invalid CCM nonce length: " ++ show ivlen let Just l = fromL (15 - ivlen) m <- parseM return (ParamsCCM c (B.convert iv) m l) parseACEParameter (GCM c) = onNextContainer Sequence $ do OctetString iv <- getNext when (B.null iv) $ throwParseError "Parsed empty GCM nonce" icvlen <- fromMaybe 12 <$> getNextMaybe intOrNothing when (icvlen < 12 || icvlen > 16) $ throwParseError $ "Parsed invalid GCM ICV length: " ++ show icvlen return (ParamsGCM c (B.convert iv) $ fromIntegral icvlen) -- | Get the authenticated-content encryption algorithm. getAuthContentEncryptionAlg :: AuthContentEncryptionParams -> AuthContentEncryptionAlg getAuthContentEncryptionAlg (Params_AUTH_ENC_128 _) = AUTH_ENC_128 getAuthContentEncryptionAlg (Params_AUTH_ENC_256 _) = AUTH_ENC_256 getAuthContentEncryptionAlg (Params_CHACHA20_POLY1305 _) = CHACHA20_POLY1305 getAuthContentEncryptionAlg (ParamsCCM c _ _ _) = CCM c getAuthContentEncryptionAlg (ParamsGCM c _ _) = GCM c -- | Generate random 'AUTH_ENC_128' parameters with the specified algorithms. generateAuthEnc128Params :: MonadRandom m => PBKDF2_PRF -> ContentEncryptionAlg -> MACAlgorithm -> m AuthContentEncryptionParams generateAuthEnc128Params prfAlg cea macAlg = do params <- generateEncryptionParams cea return $ Params_AUTH_ENC_128 $ AuthEncParams { prfAlgorithm = prfAlg , encAlgorithm = params , macAlgorithm = macAlg } -- | Generate random 'AUTH_ENC_256' parameters with the specified algorithms. generateAuthEnc256Params :: MonadRandom m => PBKDF2_PRF -> ContentEncryptionAlg -> MACAlgorithm -> m AuthContentEncryptionParams generateAuthEnc256Params prfAlg cea macAlg = do params <- generateEncryptionParams cea return $ Params_AUTH_ENC_256 $ AuthEncParams { prfAlgorithm = prfAlg , encAlgorithm = params , macAlgorithm = macAlg } -- | Generate random 'CHACHA20_POLY1305' parameters. generateChaChaPoly1305Params :: MonadRandom m => m AuthContentEncryptionParams generateChaChaPoly1305Params = do bs <- nonceGenerate 12 let iv = throwCryptoError (ChaChaPoly1305.nonce12 bs) return (Params_CHACHA20_POLY1305 iv) -- | Generate random 'CCM' parameters for the specified cipher. generateCCMParams :: (MonadRandom m, BlockCipher c) => ContentEncryptionCipher c -> CCM_M -> CCM_L -> m AuthContentEncryptionParams generateCCMParams c m l = do iv <- nonceGenerate (15 - getL l) return (ParamsCCM c iv m l) -- | Generate random 'GCM' parameters for the specified cipher. generateGCMParams :: (MonadRandom m, BlockCipher c) => ContentEncryptionCipher c -> Int -> m AuthContentEncryptionParams generateGCMParams c l = do iv <- nonceGenerate 12 return (ParamsGCM c iv l) -- | Encrypt a bytearray with the specified authenticated-content encryption -- key and algorithm. authContentEncrypt :: forall cek aad ba . (ByteArray cek, ByteArrayAccess aad, ByteArray ba) => cek -> AuthContentEncryptionParams -> ba -> aad -> ba -> Either StoreError (AuthTag, ba) authContentEncrypt key params paramsRaw aad bs = case params of Params_AUTH_ENC_128 p -> checkAuthKey 16 key >> authEncrypt p Params_AUTH_ENC_256 p -> checkAuthKey 32 key >> authEncrypt p Params_CHACHA20_POLY1305 iv -> ccpInit key iv aad >>= ccpEncrypt ParamsCCM cipher iv m l -> getAEAD cipher key (AEAD_CCM msglen m l) iv >>= encrypt (getM m) ParamsGCM cipher iv len -> getAEAD cipher key AEAD_GCM iv >>= encrypt len where msglen = B.length bs force x = x `seq` Right x encrypt :: Int -> AEAD a -> Either StoreError (AuthTag, ba) encrypt len aead = force $ aeadSimpleEncrypt aead aad bs len ccpEncrypt :: ChaChaPoly1305.State -> Either a (AuthTag, ba) ccpEncrypt state = force (found, encrypted) where (encrypted, state') = ChaChaPoly1305.encrypt bs state found = ccpTag (ChaChaPoly1305.finalize state') authEncrypt :: AuthEncParams -> Either StoreError (AuthTag, ba) authEncrypt p@AuthEncParams{..} = do let (encKey, macKey) = authKeys key p encrypted <- contentEncrypt encKey encAlgorithm bs let macMsg = paramsRaw `B.append` encrypted `B.append` B.convert aad found = mac macAlgorithm macKey macMsg return (found, encrypted) -- | Decrypt a bytearray with the specified authenticated-content encryption key -- and algorithm. authContentDecrypt :: forall cek aad ba . (ByteArray cek, ByteArrayAccess aad, ByteArray ba) => cek -> AuthContentEncryptionParams -> ba -> aad -> ba -> AuthTag -> Either StoreError ba authContentDecrypt key params paramsRaw aad bs expected = case params of Params_AUTH_ENC_128 p -> checkAuthKey 16 key >> authDecrypt p Params_AUTH_ENC_256 p -> checkAuthKey 32 key >> authDecrypt p Params_CHACHA20_POLY1305 iv -> ccpInit key iv aad >>= ccpDecrypt ParamsCCM cipher iv m l -> getAEAD cipher key (AEAD_CCM msglen m l) iv >>= decrypt (getM m) ParamsGCM cipher iv len -> getAEAD cipher key AEAD_GCM iv >>= decrypt len where msglen = B.length bs badMac = Left BadContentMAC decrypt :: Int -> AEAD a -> Either StoreError ba decrypt len aead | B.length (unAuthTag expected) /= len = badMac | otherwise = maybe badMac Right (aeadSimpleDecrypt aead aad bs expected) ccpDecrypt :: ChaChaPoly1305.State -> Either StoreError ba ccpDecrypt state | found == expected = Right decrypted | otherwise = badMac where (decrypted, state') = ChaChaPoly1305.decrypt bs state found = ccpTag (ChaChaPoly1305.finalize state') authDecrypt :: AuthEncParams -> Either StoreError ba authDecrypt p@AuthEncParams{..} | not acceptable = Left (InvalidParameter "authEnc MAC too weak") | found == expected = contentDecrypt encKey encAlgorithm bs | otherwise = badMac where (encKey, macKey) = authKeys key p macMsg = paramsRaw `B.append` bs `B.append` B.convert aad found = mac macAlgorithm macKey macMsg acceptable = securityAcceptable macAlgorithm getAEAD :: (BlockCipher cipher, ByteArray key, ByteArrayAccess iv) => proxy cipher -> key -> AEADMode -> iv -> Either StoreError (AEAD cipher) getAEAD cipher key mode iv = do c <- getCipher cipher key fromCryptoFailable $ aeadInit mode c iv authKeys :: ByteArrayAccess password => password -> AuthEncParams -> (B.ScrubbedBytes, B.ScrubbedBytes) authKeys key AuthEncParams{..} = (encKey, macKey) where encKDF = PBKDF2 "encryption" 1 Nothing prfAlgorithm encLen = getMaximumKeySize encAlgorithm encKey = kdfDerive encKDF encLen key macKDF = PBKDF2 "authentication" 1 Nothing prfAlgorithm macKey = kdfDerive macKDF macLen key -- RFC 6476 section 4.2: "Specifying a MAC key size gets a bit tricky" -- TODO: this is a hack but allows both test vectors to pass macLen | encLen == 24 = 16 | otherwise = getMaximumKeySize macAlgorithm checkAuthKey :: ByteArrayAccess cek => Int -> cek -> Either StoreError () checkAuthKey sz key | actual == sz = Right () | otherwise = Left (CryptoError CryptoError_KeySizeInvalid) where actual = B.length key ccpInit :: (ByteArrayAccess key, ByteArrayAccess aad) => key -> ChaChaPoly1305.Nonce -> aad -> Either StoreError ChaChaPoly1305.State ccpInit key nonce aad = case ChaChaPoly1305.initialize key nonce of CryptoPassed s -> return (addAAD s) CryptoFailed e -> Left (CryptoError e) where addAAD = ChaChaPoly1305.finalizeAAD . ChaChaPoly1305.appendAAD aad ccpTag :: Poly1305.Auth -> AuthTag ccpTag (Poly1305.Auth bs) = AuthTag bs -- PRF -- | Pseudorandom function used for PBKDF2. data PBKDF2_PRF = PBKDF2_SHA1 -- ^ hmacWithSHA1 | PBKDF2_SHA256 -- ^ hmacWithSHA256 | PBKDF2_SHA512 -- ^ hmacWithSHA512 deriving (Show,Eq) instance Enumerable PBKDF2_PRF where values = [ PBKDF2_SHA1 , PBKDF2_SHA256 , PBKDF2_SHA512 ] instance OIDable PBKDF2_PRF where getObjectID PBKDF2_SHA1 = [1,2,840,113549,2,7] getObjectID PBKDF2_SHA256 = [1,2,840,113549,2,9] getObjectID PBKDF2_SHA512 = [1,2,840,113549,2,11] instance OIDNameable PBKDF2_PRF where fromObjectID oid = unOIDNW <$> fromObjectID oid instance AlgorithmId PBKDF2_PRF where type AlgorithmType PBKDF2_PRF = PBKDF2_PRF algorithmName _ = "PBKDF2 PRF" algorithmType = id parameterASN1S _ = id parseParameter p = getNextMaybe nullOrNothing >> return p -- | Invoke the pseudorandom function. prf :: (ByteArrayAccess salt, ByteArrayAccess password, ByteArray out) => PBKDF2_PRF -> PBKDF2.Parameters -> password -> salt -> out prf PBKDF2_SHA1 = PBKDF2.fastPBKDF2_SHA1 prf PBKDF2_SHA256 = PBKDF2.fastPBKDF2_SHA256 prf PBKDF2_SHA512 = PBKDF2.fastPBKDF2_SHA512 -- Key derivation -- | Salt value used for key derivation. type Salt = ByteString -- | Key derivation algorithm. data KeyDerivationAlgorithm = TypePBKDF2 | TypeScrypt instance Enumerable KeyDerivationAlgorithm where values = [ TypePBKDF2 , TypeScrypt ] instance OIDable KeyDerivationAlgorithm where getObjectID TypePBKDF2 = [1,2,840,113549,1,5,12] getObjectID TypeScrypt = [1,3,6,1,4,1,11591,4,11] instance OIDNameable KeyDerivationAlgorithm where fromObjectID oid = unOIDNW <$> fromObjectID oid -- | Key derivation algorithm and associated parameters. data KeyDerivationFunc = -- | Key derivation with PBKDF2 PBKDF2 { pbkdf2Salt :: Salt -- ^ Salt value , pbkdf2IterationCount :: Int -- ^ Iteration count , pbkdf2KeyLength :: Maybe Int -- ^ Optional key length , pbkdf2Prf :: PBKDF2_PRF -- ^ Pseudorandom function } -- | Key derivation with Scrypt | Scrypt { scryptSalt :: Salt -- ^ Salt value , scryptN :: Word64 -- ^ N value , scryptR :: Int -- ^ R value , scryptP :: Int -- ^ P value , scryptKeyLength :: Maybe Int -- ^ Optional key length } deriving (Show,Eq) instance AlgorithmId KeyDerivationFunc where type AlgorithmType KeyDerivationFunc = KeyDerivationAlgorithm algorithmName _ = "key derivation algorithm" algorithmType PBKDF2{} = TypePBKDF2 algorithmType Scrypt{} = TypeScrypt parameterASN1S PBKDF2{..} = asn1Container Sequence (salt . iters . keyLen . mprf) where salt = gOctetString pbkdf2Salt iters = gIntVal (toInteger pbkdf2IterationCount) keyLen = maybe id (gIntVal . toInteger) pbkdf2KeyLength mprf = if pbkdf2Prf == PBKDF2_SHA1 then id else algorithmASN1S Sequence pbkdf2Prf parameterASN1S Scrypt{..} = asn1Container Sequence (salt . n . r . p . keyLen) where salt = gOctetString scryptSalt n = gIntVal (toInteger scryptN) r = gIntVal (toInteger scryptR) p = gIntVal (toInteger scryptP) keyLen = maybe id (gIntVal . toInteger) scryptKeyLength parseParameter TypePBKDF2 = onNextContainer Sequence $ do OctetString salt <- getNext IntVal iters <- getNext keyLen <- getNextMaybe intOrNothing b <- hasNext mprf <- if b then parseAlgorithm Sequence else return PBKDF2_SHA1 return PBKDF2 { pbkdf2Salt = salt , pbkdf2IterationCount = fromInteger iters , pbkdf2KeyLength = fromInteger <$> keyLen , pbkdf2Prf = mprf } parseParameter TypeScrypt = onNextContainer Sequence $ do OctetString salt <- getNext IntVal n <- getNext IntVal r <- getNext IntVal p <- getNext keyLen <- getNextMaybe intOrNothing return Scrypt { scryptSalt = salt , scryptN = fromInteger n , scryptR = fromInteger r , scryptP = fromInteger p , scryptKeyLength = fromInteger <$> keyLen } -- | Return the optional key length stored in the KDF parameters. kdfKeyLength :: KeyDerivationFunc -> Maybe Int kdfKeyLength PBKDF2{..} = pbkdf2KeyLength kdfKeyLength Scrypt{..} = scryptKeyLength -- | Run a key derivation function to produce a result of the specified length -- using the supplied password. kdfDerive :: (ByteArrayAccess password, ByteArray out) => KeyDerivationFunc -> Int -> password -> out kdfDerive PBKDF2{..} len pwd = prf pbkdf2Prf params pwd pbkdf2Salt where params = PBKDF2.Parameters pbkdf2IterationCount len kdfDerive Scrypt{..} len pwd = Scrypt.generate params pwd scryptSalt where params = Scrypt.Parameters { Scrypt.n = scryptN , Scrypt.r = scryptR , Scrypt.p = scryptP , Scrypt.outputLength = len } -- | Generate a random salt with the specified length in bytes. To be most -- effective, the length should be at least 8 bytes. generateSalt :: MonadRandom m => Int -> m Salt generateSalt = getRandomBytes -- Key encryption data KeyEncryptionType = TypePWRIKEK | TypeAES128_WRAP | TypeAES192_WRAP | TypeAES256_WRAP | TypeAES128_WRAP_PAD | TypeAES192_WRAP_PAD | TypeAES256_WRAP_PAD | TypeDES_EDE3_WRAP | TypeRC2_WRAP instance Enumerable KeyEncryptionType where values = [ TypePWRIKEK , TypeAES128_WRAP , TypeAES192_WRAP , TypeAES256_WRAP , TypeAES128_WRAP_PAD , TypeAES192_WRAP_PAD , TypeAES256_WRAP_PAD , TypeDES_EDE3_WRAP , TypeRC2_WRAP ] instance OIDable KeyEncryptionType where getObjectID TypePWRIKEK = [1,2,840,113549,1,9,16,3,9] getObjectID TypeAES128_WRAP = [2,16,840,1,101,3,4,1,5] getObjectID TypeAES192_WRAP = [2,16,840,1,101,3,4,1,25] getObjectID TypeAES256_WRAP = [2,16,840,1,101,3,4,1,45] getObjectID TypeAES128_WRAP_PAD = [2,16,840,1,101,3,4,1,8] getObjectID TypeAES192_WRAP_PAD = [2,16,840,1,101,3,4,1,28] getObjectID TypeAES256_WRAP_PAD = [2,16,840,1,101,3,4,1,48] getObjectID TypeDES_EDE3_WRAP = [1,2,840,113549,1,9,16,3,6] getObjectID TypeRC2_WRAP = [1,2,840,113549,1,9,16,3,7] instance OIDNameable KeyEncryptionType where fromObjectID oid = unOIDNW <$> fromObjectID oid -- | Key encryption algorithm with associated parameters (i.e. the underlying -- encryption algorithm). data KeyEncryptionParams = PWRIKEK ContentEncryptionParams -- ^ PWRI-KEK key wrap algorithm | AES128_WRAP -- ^ AES-128 key wrap | AES192_WRAP -- ^ AES-192 key wrap | AES256_WRAP -- ^ AES-256 key wrap | AES128_WRAP_PAD -- ^ AES-128 extended key wrap | AES192_WRAP_PAD -- ^ AES-192 extended key wrap | AES256_WRAP_PAD -- ^ AES-256 extended key wrap | DES_EDE3_WRAP -- ^ Triple-DES key wrap | RC2_WRAP Int -- ^ RC2 key wrap with effective key length deriving (Show,Eq) instance AlgorithmId KeyEncryptionParams where type AlgorithmType KeyEncryptionParams = KeyEncryptionType algorithmName _ = "key encryption algorithm" algorithmType (PWRIKEK _) = TypePWRIKEK algorithmType AES128_WRAP = TypeAES128_WRAP algorithmType AES192_WRAP = TypeAES192_WRAP algorithmType AES256_WRAP = TypeAES256_WRAP algorithmType AES128_WRAP_PAD = TypeAES128_WRAP_PAD algorithmType AES192_WRAP_PAD = TypeAES192_WRAP_PAD algorithmType AES256_WRAP_PAD = TypeAES256_WRAP_PAD algorithmType DES_EDE3_WRAP = TypeDES_EDE3_WRAP algorithmType (RC2_WRAP _) = TypeRC2_WRAP parameterASN1S (PWRIKEK cep) = asn1s cep parameterASN1S DES_EDE3_WRAP = gNull parameterASN1S (RC2_WRAP ekl) = rc2VersionASN1 ekl parameterASN1S _ = id parseParameter TypePWRIKEK = PWRIKEK <$> parse parseParameter TypeAES128_WRAP = return AES128_WRAP parseParameter TypeAES192_WRAP = return AES192_WRAP parseParameter TypeAES256_WRAP = return AES256_WRAP parseParameter TypeAES128_WRAP_PAD = return AES128_WRAP_PAD parseParameter TypeAES192_WRAP_PAD = return AES192_WRAP_PAD parseParameter TypeAES256_WRAP_PAD = return AES256_WRAP_PAD parseParameter TypeDES_EDE3_WRAP = getNextMaybe nullOrNothing >> return DES_EDE3_WRAP parseParameter TypeRC2_WRAP = RC2_WRAP <$> parseRC2Version instance HasKeySize KeyEncryptionParams where getKeySizeSpecifier (PWRIKEK cep) = getKeySizeSpecifier cep getKeySizeSpecifier AES128_WRAP = getCipherKeySizeSpecifier AES128 getKeySizeSpecifier AES192_WRAP = getCipherKeySizeSpecifier AES192 getKeySizeSpecifier AES256_WRAP = getCipherKeySizeSpecifier AES256 getKeySizeSpecifier AES128_WRAP_PAD = getCipherKeySizeSpecifier AES128 getKeySizeSpecifier AES192_WRAP_PAD = getCipherKeySizeSpecifier AES192 getKeySizeSpecifier AES256_WRAP_PAD = getCipherKeySizeSpecifier AES256 getKeySizeSpecifier DES_EDE3_WRAP = getCipherKeySizeSpecifier DES_EDE3 getKeySizeSpecifier (RC2_WRAP _) = KeySizeFixed 16 -- | Encrypt a key with the specified key encryption key and algorithm. keyEncrypt :: (MonadRandom m, ByteArray kek, ByteArray ba) => kek -> KeyEncryptionParams -> ba -> m (Either StoreError ba) keyEncrypt key (PWRIKEK params) bs = case params of ParamsECB cipher -> let cc = getCipher cipher key in either (return . Left) (\c -> wrapEncrypt (const . ecbEncrypt) c undefined bs) cc ParamsCBC cipher iv -> let cc = getCipher cipher key in either (return . Left) (\c -> wrapEncrypt cbcEncrypt c iv bs) cc ParamsCBCRC2 len iv -> let cc = getRC2Cipher len key in either (return . Left) (\c -> wrapEncrypt cbcEncrypt c iv bs) cc ParamsCFB cipher iv -> let cc = getCipher cipher key in either (return . Left) (\c -> wrapEncrypt cfbEncrypt c iv bs) cc ParamsCTR _ _ -> return $ Left (InvalidParameter "Unable to wrap key in CTR mode") keyEncrypt key AES128_WRAP bs = return (getCipher AES128 key >>= (`AES_KW.wrap` bs)) keyEncrypt key AES192_WRAP bs = return (getCipher AES192 key >>= (`AES_KW.wrap` bs)) keyEncrypt key AES256_WRAP bs = return (getCipher AES256 key >>= (`AES_KW.wrap` bs)) keyEncrypt key AES128_WRAP_PAD bs = return (getCipher AES128 key >>= (`AES_KW.wrapPad` bs)) keyEncrypt key AES192_WRAP_PAD bs = return (getCipher AES192 key >>= (`AES_KW.wrapPad` bs)) keyEncrypt key AES256_WRAP_PAD bs = return (getCipher AES256 key >>= (`AES_KW.wrapPad` bs)) keyEncrypt key DES_EDE3_WRAP bs = either (return . Left) (wrap3DES bs) (getCipher DES_EDE3 key) where wrap3DES b c = (\iv -> TripleDES_KW.wrap c iv b) <$> ivGenerate c keyEncrypt key (RC2_WRAP ekl) bs = either (return . Left) (wrapRC2 bs) (getRC2Cipher ekl key) where wrapRC2 b c = do iv <- ivGenerate c; RC2_KW.wrap c iv b -- | Decrypt a key with the specified key encryption key and algorithm. keyDecrypt :: (ByteArray kek, ByteArray ba) => kek -> KeyEncryptionParams -> ba -> Either StoreError ba keyDecrypt key (PWRIKEK params) bs = case params of ParamsECB cipher -> getCipher cipher key >>= (\c -> wrapDecrypt (const . ecbDecrypt) c undefined bs) ParamsCBC cipher iv -> getCipher cipher key >>= (\c -> wrapDecrypt cbcDecrypt c iv bs) ParamsCBCRC2 len iv -> getRC2Cipher len key >>= (\c -> wrapDecrypt cbcDecrypt c iv bs) ParamsCFB cipher iv -> getCipher cipher key >>= (\c -> wrapDecrypt cfbDecrypt c iv bs) ParamsCTR _ _ -> Left (InvalidParameter "Unable to unwrap key in CTR mode") keyDecrypt key AES128_WRAP bs = getCipher AES128 key >>= (`AES_KW.unwrap` bs) keyDecrypt key AES192_WRAP bs = getCipher AES192 key >>= (`AES_KW.unwrap` bs) keyDecrypt key AES256_WRAP bs = getCipher AES256 key >>= (`AES_KW.unwrap` bs) keyDecrypt key AES128_WRAP_PAD bs = getCipher AES128 key >>= (`AES_KW.unwrapPad` bs) keyDecrypt key AES192_WRAP_PAD bs = getCipher AES192 key >>= (`AES_KW.unwrapPad` bs) keyDecrypt key AES256_WRAP_PAD bs = getCipher AES256 key >>= (`AES_KW.unwrapPad` bs) keyDecrypt key DES_EDE3_WRAP bs = getCipher DES_EDE3 key >>= (`TripleDES_KW.unwrap` bs) keyDecrypt key (RC2_WRAP ekl) bs = getRC2Cipher ekl key >>= (`RC2_KW.unwrap` bs) keyWrap :: (MonadRandom m, ByteArray ba) => Int -> ba -> m (Either StoreError ba) keyWrap sz input | inLen < 3 = return $ Left (InvalidInput "keyWrap: input key too short") | inLen > 255 = return $ Left (InvalidInput "keyWrap: input key too long") | pLen == 0 = return $ Right $ B.concat [ count, check, input ] | otherwise = do padding <- getRandomBytes pLen return $ Right $ B.concat [ count, check, input, padding ] where inLen = B.length input count = B.singleton (fromIntegral inLen) check = B.xor input (B.pack [255, 255, 255] :: B.Bytes) pLen = sz - (inLen + 4) `mod` sz + comp comp = if inLen + 4 > sz then 0 else sz keyUnwrap :: ByteArray ba => ba -> Either StoreError ba keyUnwrap input | inLen < 4 = Left (InvalidInput "keyUnwrap: invalid wrapped key") | valid = Right $ B.take count (B.drop 4 input) | otherwise = Left (InvalidInput "keyUnwrap: invalid wrapped key") where inLen = B.length input count = fromIntegral (B.index input 0) bytes = [ B.index input (i + 1) `xor` B.index input (i + 4) | i <- [0..2] ] valid = foldl1 (.&.) bytes == 0xFF &&! inLen >= count - 4 wrapEncrypt :: (MonadRandom m, BlockCipher cipher, ByteArray ba) => (cipher -> IV cipher -> ba -> ba) -> cipher -> IV cipher -> ba -> m (Either StoreError ba) wrapEncrypt encFn cipher iv input = do wrapped <- keyWrap sz input return (fn <$> wrapped) where sz = blockSize cipher fn formatted = let firstPass = encFn cipher iv formatted lastBlock = B.dropView firstPass (B.length firstPass - sz) Just iv' = makeIV lastBlock in encFn cipher iv' firstPass wrapDecrypt :: (BlockCipher cipher, ByteArray ba) => (cipher -> IV cipher -> ba -> ba) -> cipher -> IV cipher -> ba -> Either StoreError ba wrapDecrypt decFn cipher iv input = keyUnwrap (decFn cipher iv firstPass) where sz = blockSize cipher (beg, lb) = B.splitAt (B.length input - sz) input lastBlock = decFn cipher iv' lb Just iv' = makeIV (B.dropView beg (B.length beg - sz)) Just iv'' = makeIV lastBlock firstPass = decFn cipher iv'' beg `B.append` lastBlock -- Key transport -- | Encryption parameters for RSAES-OAEP. data OAEPParams = OAEPParams { oaepHashAlgorithm :: DigestAlgorithm -- ^ Hash function , oaepMaskGenAlgorithm :: MaskGenerationFunc -- ^ Mask generation function } deriving (Show,Eq) instance HasStrength OAEPParams where getSecurityBits OAEPParams{..} = min (getSecurityBits oaepHashAlgorithm) (getSecurityBits oaepMaskGenAlgorithm) withOAEPParams :: forall seed output a . (ByteArrayAccess seed, ByteArray output) => OAEPParams -> (forall hash . Hash.HashAlgorithm hash => RSAOAEP.OAEPParams hash seed output -> a) -> a withOAEPParams p fn = case oaepHashAlgorithm p of DigestAlgorithm hashAlg -> fn RSAOAEP.OAEPParams { RSAOAEP.oaepHash = hashFromProxy hashAlg , RSAOAEP.oaepMaskGenAlg = mgf (oaepMaskGenAlgorithm p) , RSAOAEP.oaepLabel = Nothing } instance ASN1Elem e => ProduceASN1Object e OAEPParams where asn1s OAEPParams{..} = asn1Container Sequence (h . m) where sha1 = DigestAlgorithm SHA1 tag i = asn1Container (Container Context i) h | oaepHashAlgorithm == sha1 = id | otherwise = tag 0 (algorithmASN1S Sequence oaepHashAlgorithm) m | oaepMaskGenAlgorithm == MGF1 sha1 = id | otherwise = tag 1 (algorithmASN1S Sequence oaepMaskGenAlgorithm) instance Monoid e => ParseASN1Object e OAEPParams where parse = onNextContainer Sequence $ do h <- tag 0 (parseAlgorithm Sequence) m <- tag 1 (parseAlgorithm Sequence) _ <- tag 2 parsePSpecified return OAEPParams { oaepHashAlgorithm = fromMaybe sha1 h , oaepMaskGenAlgorithm = fromMaybe (MGF1 sha1) m } where sha1 = DigestAlgorithm SHA1 tag i = onNextContainerMaybe (Container Context i) parsePSpecified = do OID [1,2,840,113549,1,1,9] <- getNext OctetString p <- getNext guard (B.null p) data KeyTransportType = TypeRSAES | TypeRSAESOAEP instance Enumerable KeyTransportType where values = [ TypeRSAES , TypeRSAESOAEP ] instance OIDable KeyTransportType where getObjectID TypeRSAES = [1,2,840,113549,1,1,1] getObjectID TypeRSAESOAEP = [1,2,840,113549,1,1,7] instance OIDNameable KeyTransportType where fromObjectID oid = unOIDNW <$> fromObjectID oid -- | Key transport algorithm with associated parameters. data KeyTransportParams = RSAES -- ^ RSAES-PKCS1 | RSAESOAEP OAEPParams -- ^ RSAES-OAEP deriving (Show,Eq) instance AlgorithmId KeyTransportParams where type AlgorithmType KeyTransportParams = KeyTransportType algorithmName _ = "key transport algorithm" algorithmType RSAES = TypeRSAES algorithmType (RSAESOAEP _) = TypeRSAESOAEP parameterASN1S RSAES = gNull parameterASN1S (RSAESOAEP p) = asn1s p parseParameter TypeRSAES = getNextMaybe nullOrNothing >> return RSAES parseParameter TypeRSAESOAEP = RSAESOAEP <$> parse -- | Encrypt the specified content with a key-transport algorithm and recipient -- public key. transportEncrypt :: MonadRandom m => KeyTransportParams -> X509.PubKey -> ByteString -> m (Either StoreError ByteString) transportEncrypt RSAES (X509.PubKeyRSA pub) bs = mapLeft RSAError <$> RSA.encrypt pub bs transportEncrypt (RSAESOAEP p) (X509.PubKeyRSA pub) bs = withOAEPParams p $ \params -> mapLeft RSAError <$> RSAOAEP.encrypt params pub bs transportEncrypt _ _ _ = return $ Left UnexpectedPublicKeyType -- | Decrypt the specified content with a key-transport algorithm and recipient -- private key. transportDecrypt :: MonadRandom m => KeyTransportParams -> X509.PrivKey -> ByteString -> m (Either StoreError ByteString) transportDecrypt RSAES (X509.PrivKeyRSA priv) bs = mapLeft RSAError <$> RSA.decryptSafer priv bs transportDecrypt (RSAESOAEP p) (X509.PrivKeyRSA priv) bs | securityAcceptable p = withOAEPParams p $ \params -> mapLeft RSAError <$> RSAOAEP.decryptSafer params priv bs | otherwise = return $ Left (InvalidParameter "OAEP parameters too weak") transportDecrypt _ _ _ = return $ Left UnexpectedPrivateKeyType -- Key agreement -- | Key derivation function used for key agreement. data KeyAgreementKDF = forall hashAlg . Hash.HashAlgorithm hashAlg => KA_X963_KDF (DigestProxy hashAlg) -- ^ ANSI-X9.63-KDF key derivation function | forall hashAlg . Hash.HashAlgorithm hashAlg => KA_HKDF (DigestProxy hashAlg) -- ^ Extract-and-Expand HMAC-based key derivation function deriving instance Show KeyAgreementKDF instance Eq KeyAgreementKDF where KA_X963_KDF a == KA_X963_KDF b = DigestAlgorithm a == DigestAlgorithm b KA_HKDF a == KA_HKDF b = DigestAlgorithm a == DigestAlgorithm b _ == _ = False data KeyAgreementType = TypeStdDH KeyAgreementKDF | TypeCofactorDH KeyAgreementKDF deriving (Show,Eq) instance Enumerable KeyAgreementType where values = [ TypeStdDH (KA_X963_KDF SHA1) , TypeStdDH (KA_X963_KDF SHA224) , TypeStdDH (KA_X963_KDF SHA256) , TypeStdDH (KA_X963_KDF SHA384) , TypeStdDH (KA_X963_KDF SHA512) , TypeCofactorDH (KA_X963_KDF SHA1) , TypeCofactorDH (KA_X963_KDF SHA224) , TypeCofactorDH (KA_X963_KDF SHA256) , TypeCofactorDH (KA_X963_KDF SHA384) , TypeCofactorDH (KA_X963_KDF SHA512) , TypeStdDH (KA_HKDF SHA256) , TypeStdDH (KA_HKDF SHA384) , TypeStdDH (KA_HKDF SHA512) ] instance OIDable KeyAgreementType where getObjectID (TypeStdDH (KA_X963_KDF SHA1)) = [1,3,133,16,840,63,0,2] getObjectID (TypeStdDH (KA_X963_KDF SHA224)) = [1,3,132,1,11,0] getObjectID (TypeStdDH (KA_X963_KDF SHA256)) = [1,3,132,1,11,1] getObjectID (TypeStdDH (KA_X963_KDF SHA384)) = [1,3,132,1,11,2] getObjectID (TypeStdDH (KA_X963_KDF SHA512)) = [1,3,132,1,11,3] getObjectID (TypeCofactorDH (KA_X963_KDF SHA1)) = [1,3,133,16,840,63,0,3] getObjectID (TypeCofactorDH (KA_X963_KDF SHA224)) = [1,3,132,1,14,0] getObjectID (TypeCofactorDH (KA_X963_KDF SHA256)) = [1,3,132,1,14,1] getObjectID (TypeCofactorDH (KA_X963_KDF SHA384)) = [1,3,132,1,14,2] getObjectID (TypeCofactorDH (KA_X963_KDF SHA512)) = [1,3,132,1,14,3] getObjectID (TypeStdDH (KA_HKDF SHA256)) = [1,2,840,113549,1,9,16,3,19] getObjectID (TypeStdDH (KA_HKDF SHA384)) = [1,2,840,113549,1,9,16,3,20] getObjectID (TypeStdDH (KA_HKDF SHA512)) = [1,2,840,113549,1,9,16,3,21] getObjectID ty = error ("Unsupported KeyAgreementType: " ++ show ty) instance OIDNameable KeyAgreementType where fromObjectID oid = unOIDNW <$> fromObjectID oid -- | Key agreement algorithm with associated parameters. data KeyAgreementParams = StdDH KeyAgreementKDF KeyEncryptionParams -- ^ 1-Pass D-H with Stardard ECDH | CofactorDH KeyAgreementKDF KeyEncryptionParams -- ^ 1-Pass D-H with Cofactor ECDH deriving (Show,Eq) instance AlgorithmId KeyAgreementParams where type AlgorithmType KeyAgreementParams = KeyAgreementType algorithmName _ = "key agreement algorithm" algorithmType (StdDH d _) = TypeStdDH d algorithmType (CofactorDH d _) = TypeCofactorDH d parameterASN1S (StdDH _ p) = algorithmASN1S Sequence p parameterASN1S (CofactorDH _ p) = algorithmASN1S Sequence p parseParameter (TypeStdDH d) = StdDH d <$> parseAlgorithm Sequence parseParameter (TypeCofactorDH d) = CofactorDH d <$> parseAlgorithm Sequence ecdhKeyMaterial :: (ByteArrayAccess bin, ByteArray bout) => KeyAgreementKDF -> KeyEncryptionParams -> Maybe ByteString -> bin -> bout ecdhKeyMaterial kdf kep ukm zz = case kdf of KA_HKDF hashAlg -> HKDF.expand (extract hashAlg zz) otherInfo outLen KA_X963_KDF hashAlg | r == 0 -> B.concat (map chunk [1..d]) | otherwise -> B.concat (map chunk [1..d]) `B.append` B.take r (chunk $ succ d) where (d, r) = outLen `divMod` Hash.hashDigestSize prx prx = hashFromProxy hashAlg chunk = B.convert . Hash.hashFinalize . hashCtx hashCtx' = Hash.hashUpdate (Hash.hashInitWith prx) zz hashCtx i = Hash.hashUpdate (Hash.hashUpdate hashCtx' $ toWord32 i) otherInfo where outLen = getMaximumKeySize kep outBits = 8 * outLen toWord32 = i2ospOf_ 4 . fromIntegral extract :: (Hash.HashAlgorithm a, ByteArrayAccess ikm) => DigestProxy a -> ikm -> HKDF.PRK a extract _ = HKDF.extract (fromMaybe B.empty ukm) otherInfo = let ki = algorithmASN1S Sequence kep eui = case ukm of Nothing -> id Just bs -> asn1Container (Container Context 0) (gOctetString bs) spi = asn1Container (Container Context 2) (gOctetString $ toWord32 outBits) in encodeASN1S $ asn1Container Sequence (ki . eui . spi) -- | Key pair for ECDH. data ECDHPair = PairEC ECC.Curve ECC.PrivateNumber ECC.Point | PairX25519 X25519.SecretKey X25519.PublicKey | PairX448 X448.SecretKey X448.PublicKey -- | Generate an ephemeral ECDH key. ecdhGenerate :: MonadRandom m => X509.PubKey -> m (Either StoreError ECDHPair) ecdhGenerate (X509.PubKeyEC pub) = case ecPubKeyCurveName pub of Nothing -> return $ Left NamedCurveRequired Just n -> do let curve = ECC.getCurveByName n priv <- ECDH.generatePrivate curve return $ case unserializePoint curve (X509.pubkeyEC_pub pub) of Nothing -> Left (InvalidInput "Invalid serialized point") Just pt -> Right (PairEC curve priv pt) ecdhGenerate (X509.PubKeyX25519 pub) = do priv <- X25519.generateSecretKey return $ Right (PairX25519 priv pub) ecdhGenerate (X509.PubKeyX448 pub) = do priv <- X448.generateSecretKey return $ Right (PairX448 priv pub) ecdhGenerate _ = return $ Left UnexpectedPublicKeyType -- | Return the serialized public key corresponding to the ECDH private key. ecdhPublic :: ECDHPair -> ByteString ecdhPublic (PairEC curve d _) = unSerialize (getSerializedPoint curve d) where unSerialize (X509.SerializedPoint pt) = pt ecdhPublic (PairX25519 priv _) = B.convert (X25519.toPublic priv) ecdhPublic (PairX448 priv _) = B.convert (X448.toPublic priv) -- | Encrypt the specified content with an ECDH key pair and key-agreement -- algorithm. ecdhEncrypt :: (MonadRandom m, ByteArray ba) => KeyAgreementParams -> Maybe ByteString -> ECDHPair -> ba -> m (Either StoreError ba) ecdhEncrypt (StdDH dig kep) ukm (PairEC curve d pub) bs = do let s = ECDH.getShared curve d pub k = ecdhKeyMaterial dig kep ukm s :: B.ScrubbedBytes keyEncrypt k kep bs ecdhEncrypt (StdDH dig kep) ukm (PairX25519 priv pub) bs = case fromCryptoFailable (ecdh x25519 priv pub) of Left e -> return (Left e) Right s -> let k = ecdhKeyMaterial dig kep ukm s :: B.ScrubbedBytes in keyEncrypt k kep bs ecdhEncrypt (StdDH dig kep) ukm (PairX448 priv pub) bs = case fromCryptoFailable (ecdh x448 priv pub) of Left e -> return (Left e) Right s -> let k = ecdhKeyMaterial dig kep ukm s :: B.ScrubbedBytes in keyEncrypt k kep bs ecdhEncrypt (CofactorDH dig kep) ukm (PairEC curve d pub) bs = do let h = ECC.ecc_h (ECC.common_curve curve) s = ECDH.getShared curve (h * d) pub k = ecdhKeyMaterial dig kep ukm s :: B.ScrubbedBytes keyEncrypt k kep bs ecdhEncrypt (CofactorDH _ _) _ (PairX25519 _ _) _ = return $ Left (InvalidInput "X25519 is not supported for cofactor DH") ecdhEncrypt (CofactorDH _ _) _ (PairX448 _ _) _ = return $ Left (InvalidInput "X448 is not supported for cofactor DH") -- | Decrypt the specified content with an ECDH key pair and key-agreement -- algorithm. ecdhDecrypt :: ByteArray ba => KeyAgreementParams -> Maybe ByteString -> X509.PrivKey -> ByteString -> ba -> Either StoreError ba ecdhDecrypt (StdDH dig kep) ukm (X509.PrivKeyEC priv) pt bs = case ecPrivKeyCurve priv of Nothing -> Left UnsupportedEllipticCurve Just curve -> case unserializePoint curve (X509.SerializedPoint pt) of Nothing -> Left (InvalidInput "Invalid serialized point") Just pub -> do let d = X509.privkeyEC_priv priv s = ECDH.getShared curve d pub k = ecdhKeyMaterial dig kep ukm s :: B.ScrubbedBytes keyDecrypt k kep bs ecdhDecrypt (StdDH dig kep) ukm (X509.PrivKeyX25519 priv) pt bs = do s <- fromCryptoFailable (X25519.publicKey pt >>= ecdh x25519 priv) let k = ecdhKeyMaterial dig kep ukm s :: B.ScrubbedBytes keyDecrypt k kep bs ecdhDecrypt (StdDH dig kep) ukm (X509.PrivKeyX448 priv) pt bs = do s <- fromCryptoFailable (X448.publicKey pt >>= ecdh x448 priv) let k = ecdhKeyMaterial dig kep ukm s :: B.ScrubbedBytes keyDecrypt k kep bs ecdhDecrypt (StdDH _ _) _ _ _ _ = Left UnexpectedPrivateKeyType ecdhDecrypt (CofactorDH dig kep) ukm (X509.PrivKeyEC priv) pt bs = case ecPrivKeyCurve priv of Nothing -> Left UnsupportedEllipticCurve Just curve -> case unserializePoint curve (X509.SerializedPoint pt) of Nothing -> Left (InvalidInput "Invalid serialized point") Just pub -> do let h = ECC.ecc_h (ECC.common_curve curve) d = X509.privkeyEC_priv priv s = ECDH.getShared curve (h * d) pub k = ecdhKeyMaterial dig kep ukm s :: B.ScrubbedBytes keyDecrypt k kep bs ecdhDecrypt (CofactorDH _ _) _ _ _ _ = Left UnexpectedPrivateKeyType x25519 :: Proxy Curve_X25519 x25519 = Proxy x448 :: Proxy Curve_X448 x448 = Proxy -- Utilities getCipher :: (BlockCipher cipher, ByteArray key) => proxy cipher -> key -> Either StoreError cipher getCipher _ key = fromCryptoFailable (cipherInit key) getRC2Cipher :: ByteArray key => Int -> key -> Either StoreError RC2 getRC2Cipher len key = fromCryptoFailable (rc2WithEffectiveKeyLength len key) ivGenerate :: (BlockCipher cipher, MonadRandom m) => cipher -> m (IV cipher) ivGenerate cipher = do bs <- getRandomBytes (blockSize cipher) let Just iv = makeIV (bs :: ByteString) return iv nonceGenerate :: MonadRandom m => Int -> m B.Bytes nonceGenerate = getRandomBytes cipherFromProxy :: proxy cipher -> cipher cipherFromProxy _ = undefined -- | Return the block size of the specified block cipher. proxyBlockSize :: BlockCipher cipher => proxy cipher -> Int proxyBlockSize = blockSize . cipherFromProxy getL :: CCM_L -> Int getL CCM_L2 = 2 getL CCM_L3 = 3 getL CCM_L4 = 4 getM :: CCM_M -> Int getM CCM_M4 = 4 getM CCM_M6 = 6 getM CCM_M8 = 8 getM CCM_M10 = 10 getM CCM_M12 = 12 getM CCM_M14 = 14 getM CCM_M16 = 16 fromL :: Int -> Maybe CCM_L fromL 2 = Just CCM_L2 fromL 3 = Just CCM_L3 fromL 4 = Just CCM_L4 fromL _ = Nothing parseM :: Monoid e => ParseASN1 e CCM_M parseM = do IntVal l <- getNext case l of 4 -> return CCM_M4 6 -> return CCM_M6 8 -> return CCM_M8 10 -> return CCM_M10 12 -> return CCM_M12 14 -> return CCM_M14 16 -> return CCM_M16 i -> throwParseError ("Parsed invalid CCM parameter M: " ++ show i) -- Mask generation functions data MaskGenerationType = TypeMGF1 deriving (Show,Eq) instance Enumerable MaskGenerationType where values = [ TypeMGF1 ] instance OIDable MaskGenerationType where getObjectID TypeMGF1 = [1,2,840,113549,1,1,8] instance OIDNameable MaskGenerationType where fromObjectID oid = unOIDNW <$> fromObjectID oid -- | Mask Generation Functions (MGF) and associated parameters. newtype MaskGenerationFunc = MGF1 DigestAlgorithm deriving (Show,Eq) instance HasStrength MaskGenerationFunc where getSecurityBits (MGF1 d) = getSecurityBits d instance AlgorithmId MaskGenerationFunc where type AlgorithmType MaskGenerationFunc = MaskGenerationType algorithmName _ = "mask generation function" algorithmType (MGF1 _) = TypeMGF1 parameterASN1S (MGF1 d) = algorithmASN1S Sequence d parseParameter TypeMGF1 = MGF1 <$> parseAlgorithm Sequence -- | Generate a mask with the MGF. mgf :: (ByteArrayAccess seed, ByteArray output) => MaskGenerationFunc -> seed -> Int -> output mgf (MGF1 (DigestAlgorithm hashAlg)) = MGF.mgf1 (hashFromProxy hashAlg) -- Signature algorithms -- | Signature value. type SignatureValue = ByteString -- | Signature parameters for RSASSA-PSS. data PSSParams = PSSParams { pssHashAlgorithm :: DigestAlgorithm -- ^ Hash function , pssMaskGenAlgorithm :: MaskGenerationFunc -- ^ Mask generation function , pssSaltLength :: Int -- ^ Length of the salt in bytes } deriving (Show,Eq) instance HasStrength PSSParams where getSecurityBits PSSParams{..} = min (getSecurityBits pssHashAlgorithm) (getSecurityBits pssMaskGenAlgorithm) withPSSParams :: forall seed output a . (ByteArrayAccess seed, ByteArray output) => PSSParams -> (forall hash . Hash.HashAlgorithm hash => RSAPSS.PSSParams hash seed output -> a) -> a withPSSParams p fn = case pssHashAlgorithm p of DigestAlgorithm hashAlg -> fn RSAPSS.PSSParams { RSAPSS.pssHash = hashFromProxy hashAlg , RSAPSS.pssMaskGenAlg = mgf (pssMaskGenAlgorithm p) , RSAPSS.pssSaltLength = pssSaltLength p , RSAPSS.pssTrailerField = 0xbc } instance ASN1Elem e => ProduceASN1Object e PSSParams where asn1s PSSParams{..} = asn1Container Sequence (h . m . s) where sha1 = DigestAlgorithm SHA1 tag i = asn1Container (Container Context i) h | pssHashAlgorithm == sha1 = id | otherwise = tag 0 (algorithmASN1S Sequence pssHashAlgorithm) m | pssMaskGenAlgorithm == MGF1 sha1 = id | otherwise = tag 1 (algorithmASN1S Sequence pssMaskGenAlgorithm) s | pssSaltLength == 20 && pssHashAlgorithm == sha1 = id | otherwise = tag 2 (gIntVal $ fromIntegral pssSaltLength) instance Monoid e => ParseASN1Object e PSSParams where parse = onNextContainer Sequence $ do h <- tag 0 (parseAlgorithm Sequence) m <- tag 1 (parseAlgorithm Sequence) s <- tag 2 $ do { IntVal i <- getNext; return (fromIntegral i) } _ <- tag 3 $ do { IntVal 1 <- getNext; return () } return PSSParams { pssHashAlgorithm = fromMaybe sha1 h , pssMaskGenAlgorithm = fromMaybe (MGF1 sha1) m , pssSaltLength = fromMaybe 20 s } where sha1 = DigestAlgorithm SHA1 tag i = onNextContainerMaybe (Container Context i) data SignatureType = TypeRSAAnyHash | TypeRSA DigestAlgorithm | TypeRSAPSS | TypeDSA DigestAlgorithm | TypeECDSA DigestAlgorithm | TypeEd25519 | TypeEd448 deriving (Show,Eq) instance Enumerable SignatureType where values = [ TypeRSAAnyHash , TypeRSA (DigestAlgorithm MD2) , TypeRSA (DigestAlgorithm MD5) , TypeRSA (DigestAlgorithm SHA1) , TypeRSA (DigestAlgorithm SHA224) , TypeRSA (DigestAlgorithm SHA256) , TypeRSA (DigestAlgorithm SHA384) , TypeRSA (DigestAlgorithm SHA512) , TypeRSAPSS , TypeDSA (DigestAlgorithm SHA1) , TypeDSA (DigestAlgorithm SHA224) , TypeDSA (DigestAlgorithm SHA256) , TypeECDSA (DigestAlgorithm SHA1) , TypeECDSA (DigestAlgorithm SHA224) , TypeECDSA (DigestAlgorithm SHA256) , TypeECDSA (DigestAlgorithm SHA384) , TypeECDSA (DigestAlgorithm SHA512) , TypeEd25519 , TypeEd448 ] instance OIDable SignatureType where getObjectID TypeRSAAnyHash = [1,2,840,113549,1,1,1] getObjectID (TypeRSA (DigestAlgorithm MD2)) = [1,2,840,113549,1,1,2] getObjectID (TypeRSA (DigestAlgorithm MD5)) = [1,2,840,113549,1,1,4] getObjectID (TypeRSA (DigestAlgorithm SHA1)) = [1,2,840,113549,1,1,5] getObjectID (TypeRSA (DigestAlgorithm SHA224)) = [1,2,840,113549,1,1,14] getObjectID (TypeRSA (DigestAlgorithm SHA256)) = [1,2,840,113549,1,1,11] getObjectID (TypeRSA (DigestAlgorithm SHA384)) = [1,2,840,113549,1,1,12] getObjectID (TypeRSA (DigestAlgorithm SHA512)) = [1,2,840,113549,1,1,13] getObjectID TypeRSAPSS = [1,2,840,113549,1,1,10] getObjectID (TypeDSA (DigestAlgorithm SHA1)) = [1,2,840,10040,4,3] getObjectID (TypeDSA (DigestAlgorithm SHA224)) = [2,16,840,1,101,3,4,3,1] getObjectID (TypeDSA (DigestAlgorithm SHA256)) = [2,16,840,1,101,3,4,3,2] getObjectID (TypeECDSA (DigestAlgorithm SHA1)) = [1,2,840,10045,4,1] getObjectID (TypeECDSA (DigestAlgorithm SHA224)) = [1,2,840,10045,4,3,1] getObjectID (TypeECDSA (DigestAlgorithm SHA256)) = [1,2,840,10045,4,3,2] getObjectID (TypeECDSA (DigestAlgorithm SHA384)) = [1,2,840,10045,4,3,3] getObjectID (TypeECDSA (DigestAlgorithm SHA512)) = [1,2,840,10045,4,3,4] getObjectID TypeEd25519 = [1,3,101,112] getObjectID TypeEd448 = [1,3,101,113] getObjectID ty = error ("Unsupported SignatureType: " ++ show ty) instance OIDNameable SignatureType where fromObjectID oid = unOIDNW <$> fromObjectID oid -- | CMS signature algorithms and associated parameters. data SignatureAlg = RSAAnyHash | RSA DigestAlgorithm | RSAPSS PSSParams | DSA DigestAlgorithm | ECDSA DigestAlgorithm | Ed25519 | Ed448 deriving (Show,Eq) instance AlgorithmId SignatureAlg where type AlgorithmType SignatureAlg = SignatureType algorithmName _ = "signature algorithm" algorithmType RSAAnyHash = TypeRSAAnyHash algorithmType (RSA alg) = TypeRSA alg algorithmType (RSAPSS _) = TypeRSAPSS algorithmType (DSA alg) = TypeDSA alg algorithmType (ECDSA alg) = TypeECDSA alg algorithmType Ed25519 = TypeEd25519 algorithmType Ed448 = TypeEd448 parameterASN1S RSAAnyHash = gNull parameterASN1S (RSA _) = gNull parameterASN1S (RSAPSS p) = asn1s p parameterASN1S (DSA _) = id parameterASN1S (ECDSA _) = id parameterASN1S Ed25519 = id parameterASN1S Ed448 = id parseParameter TypeRSAAnyHash = getNextMaybe nullOrNothing >> return RSAAnyHash parseParameter (TypeRSA alg) = getNextMaybe nullOrNothing >> return (RSA alg) parseParameter TypeRSAPSS = RSAPSS <$> parse parseParameter (TypeDSA alg) = return (DSA alg) parseParameter (TypeECDSA alg) = return (ECDSA alg) parseParameter TypeEd25519 = return Ed25519 parseParameter TypeEd448 = return Ed448 -- | Sign a message using the specified algorithm and private key. The -- corresponding public key is also required for some algorithms. signatureGenerate :: MonadRandom m => SignatureAlg -> X509.PrivKey -> X509.PubKey -> ByteString -> m (Either StoreError SignatureValue) signatureGenerate RSAAnyHash _ _ _ = error "signatureGenerate: should call signatureResolveHash first" signatureGenerate (RSA alg) (X509.PrivKeyRSA priv) (X509.PubKeyRSA _) msg = let err = return . Left $ InvalidParameter ("Invalid hash algorithm for RSA: " ++ show alg) in withHashAlgorithmASN1 alg err $ \hashAlg -> mapLeft RSAError <$> RSA.signSafer (Just hashAlg) priv msg signatureGenerate (RSAPSS p) (X509.PrivKeyRSA priv) (X509.PubKeyRSA _) msg = withPSSParams p $ \params -> mapLeft RSAError <$> RSAPSS.signSafer params priv msg signatureGenerate (DSA alg) (X509.PrivKeyDSA priv) (X509.PubKeyDSA _) msg = case alg of DigestAlgorithm t -> Right . dsaFromSignature <$> DSA.sign priv (hashFromProxy t) msg signatureGenerate (ECDSA alg) (X509.PrivKeyEC priv) (X509.PubKeyEC _) msg = case alg of DigestAlgorithm t -> case ecdsaToPrivateKey priv of Nothing -> return (Left UnsupportedEllipticCurve) Just p -> let h = hashFromProxy t in Right . ecdsaFromSignature <$> ECDSA.sign p h msg signatureGenerate Ed25519 (X509.PrivKeyEd25519 priv) (X509.PubKeyEd25519 pub) msg = return . Right . B.convert $ Ed25519.sign priv pub msg signatureGenerate Ed448 (X509.PrivKeyEd448 priv) (X509.PubKeyEd448 pub) msg = return . Right . B.convert $ Ed448.sign priv pub msg signatureGenerate _ _ _ _ = return (Left UnexpectedPrivateKeyType) -- | Verify a message signature using the specified algorithm and public key. signatureVerify :: SignatureAlg -> X509.PubKey -> ByteString -> SignatureValue -> Bool signatureVerify RSAAnyHash _ _ _ = error "signatureVerify: should call signatureResolveHash first" signatureVerify (RSA alg) (X509.PubKeyRSA pub) msg sig = withHashAlgorithmASN1 alg False $ \hashAlg -> RSA.verify (Just hashAlg) pub msg sig signatureVerify (RSAPSS p) (X509.PubKeyRSA pub) msg sig | securityAcceptable p = withPSSParams p $ \params -> RSAPSS.verify params pub msg sig | otherwise = False signatureVerify (DSA alg) (X509.PubKeyDSA pub) msg sig = fromMaybe False $ do s <- dsaToSignature sig case alg of DigestAlgorithm t -> return $ DSA.verify (hashFromProxy t) pub s msg signatureVerify (ECDSA alg) (X509.PubKeyEC pub) msg sig = fromMaybe False $ do p <- ecdsaToPublicKey pub s <- ecdsaToSignature sig case alg of DigestAlgorithm t -> return $ ECDSA.verify (hashFromProxy t) p s msg signatureVerify Ed25519 (X509.PubKeyEd25519 pub) msg sig = case Ed25519.signature sig of CryptoFailed _ -> False CryptoPassed s -> Ed25519.verify pub msg s signatureVerify Ed448 (X509.PubKeyEd448 pub) msg sig = case Ed448.signature sig of CryptoFailed _ -> False CryptoPassed s -> Ed448.verify pub msg s signatureVerify _ _ _ _ = False withHashAlgorithmASN1 :: DigestAlgorithm -> a -> (forall hashAlg . RSA.HashAlgorithmASN1 hashAlg => hashAlg -> a) -> a withHashAlgorithmASN1 (DigestAlgorithm MD2) _ f = f Hash.MD2 withHashAlgorithmASN1 (DigestAlgorithm MD5) _ f = f Hash.MD5 withHashAlgorithmASN1 (DigestAlgorithm SHA1) _ f = f Hash.SHA1 withHashAlgorithmASN1 (DigestAlgorithm SHA224) _ f = f Hash.SHA224 withHashAlgorithmASN1 (DigestAlgorithm SHA256) _ f = f Hash.SHA256 withHashAlgorithmASN1 (DigestAlgorithm SHA384) _ f = f Hash.SHA384 withHashAlgorithmASN1 (DigestAlgorithm SHA512) _ f = f Hash.SHA512 withHashAlgorithmASN1 _ e _ = e -- | Return on which digest algorithm the specified signature algorithm is -- based, as well as a substitution algorithm for when a default digest -- algorithm is required. signatureResolveHash :: Bool -> DigestAlgorithm -> SignatureAlg -> (DigestAlgorithm, SignatureAlg) signatureResolveHash _ d RSAAnyHash = (d, RSA d) signatureResolveHash _ _ alg@(RSA d) = (d, alg) signatureResolveHash _ _ alg@(RSAPSS p) = (pssHashAlgorithm p, alg) signatureResolveHash _ _ alg@(DSA d) = (d, alg) signatureResolveHash _ _ alg@(ECDSA d) = (d, alg) signatureResolveHash _ _ alg@Ed25519 = (DigestAlgorithm SHA512, alg) signatureResolveHash True _ alg@Ed448 = (DigestAlgorithm SHAKE256_512, alg) signatureResolveHash False _ alg@Ed448 = (DigestAlgorithm (SHAKE256 p512), alg) -- | Check that a signature algorithm is based on the specified digest algorithm -- and return a substitution algorithm for when a default digest algorithm is -- required. signatureCheckHash :: DigestAlgorithm -> SignatureAlg -> Maybe SignatureAlg signatureCheckHash expected RSAAnyHash = Just $ RSA expected signatureCheckHash expected alg@(RSA found) | expected == found = Just alg | otherwise = Nothing signatureCheckHash expected alg@(RSAPSS p) | expected == pssHashAlgorithm p = Just alg | otherwise = Nothing signatureCheckHash expected alg@(DSA found) | expected == found = Just alg | otherwise = Nothing signatureCheckHash expected alg@(ECDSA found) | expected == found = Just alg | otherwise = Nothing signatureCheckHash expected alg@Ed25519 | expected == DigestAlgorithm SHA512 = Just alg | otherwise = Nothing signatureCheckHash expected alg@Ed448 | expected == DigestAlgorithm SHAKE256_512 = Just alg | expected == DigestAlgorithm (SHAKE256 p512) = Just alg | otherwise = Nothing dsaToSignature :: ByteString -> Maybe DSA.Signature dsaToSignature b = tryDecodeAndParse b $ onNextContainer Sequence $ do IntVal r <- getNext IntVal s <- getNext return DSA.Signature { DSA.sign_r = r, DSA.sign_s = s } dsaFromSignature :: DSA.Signature -> ByteString dsaFromSignature sig = encodeASN1S $ asn1Container Sequence (gIntVal (DSA.sign_r sig) . gIntVal (DSA.sign_s sig)) ecdsaToSignature :: ByteString -> Maybe ECDSA.Signature ecdsaToSignature b = tryDecodeAndParse b $ onNextContainer Sequence $ do IntVal r <- getNext IntVal s <- getNext return ECDSA.Signature { ECDSA.sign_r = r, ECDSA.sign_s = s } ecdsaFromSignature :: ECDSA.Signature -> ByteString ecdsaFromSignature sig = encodeASN1S $ asn1Container Sequence (gIntVal (ECDSA.sign_r sig) . gIntVal (ECDSA.sign_s sig)) ecdsaToPublicKey :: X509.PubKeyEC -> Maybe ECDSA.PublicKey ecdsaToPublicKey key = do curve <- ecPubKeyCurve key pt <- unserializePoint curve (X509.pubkeyEC_pub key) return ECDSA.PublicKey { ECDSA.public_curve = curve, ECDSA.public_q = pt } ecdsaToPrivateKey :: X509.PrivKeyEC -> Maybe ECDSA.PrivateKey ecdsaToPrivateKey key = do curve <- ecPrivKeyCurve key let d = X509.privkeyEC_priv key return ECDSA.PrivateKey { ECDSA.private_curve = curve, ECDSA.private_d = d } tryDecodeAndParse :: ByteString -> ParseASN1 () a -> Maybe a tryDecodeAndParse b parser = either (const Nothing) Just $ case decodeASN1' BER b of Left _ -> Left undefined -- value ignored Right asn1 -> runParseASN1 parser asn1 cryptostore-0.3.1.0/src/Crypto/Store/CMS/Attribute.hs0000644000000000000000000001344107346545000020526 0ustar0000000000000000-- | -- Module : Crypto.Store.CMS.Attribute -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- CMS attributes {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RecordWildCards #-} module Crypto.Store.CMS.Attribute ( Attribute(..) , attributesASN1S , parseAttributes -- * Generic attribute , findAttribute , setAttribute , filterAttributes -- * Implementing attributes , setAttributeASN1S , runParseAttribute -- * Standard attributes , getContentTypeAttr , setContentTypeAttr , getMessageDigestAttr , setMessageDigestAttr , getSigningTimeAttr , setSigningTimeAttr , setSigningTimeAttrCurrent ) where import Control.Monad.IO.Class import Data.ASN1.Types import Data.ByteString (ByteString) import Data.Hourglass import Data.Maybe (fromMaybe) import System.Hourglass (dateCurrent) import Crypto.Store.ASN1.Generate import Crypto.Store.ASN1.Parse import Crypto.Store.CMS.Type import Crypto.Store.CMS.Util -- | An attribute extending the parent structure with arbitrary data. data Attribute = Attribute { attrType :: OID -- ^ Attribute type , attrValues :: [ASN1] -- ^ Attribute values } deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e Attribute where asn1s Attribute{..} = asn1Container Sequence (gOID attrType . asn1Container Set (gMany attrValues)) instance Monoid e => ParseASN1Object e Attribute where parse = onNextContainer Sequence $ do OID oid <- getNext vals <- onNextContainer Set (getMany getNext) return Attribute { attrType = oid, attrValues = vals } -- | Produce the ASN.1 stream for a list of attributes. attributesASN1S :: ASN1Elem e => ASN1ConstructionType -> [Attribute] -> ASN1Stream e attributesASN1S _ [] = id attributesASN1S ty attrs = asn1Container ty (asn1s attrs) -- | Parse a list of attributes. parseAttributes :: Monoid e => ASN1ConstructionType -> ParseASN1 e [Attribute] parseAttributes ty = fromMaybe [] <$> onNextContainerMaybe ty parse -- | Return the values for the first attribute with the specified type. findAttribute :: OID -> [Attribute] -> Maybe [ASN1] findAttribute oid attrs = case [ attrValues a | a <- attrs, attrType a == oid ] of [] -> Nothing (v:_) -> Just v -- | Filter a list of attributes based on a predicate applied to attribute type. filterAttributes :: (OID -> Bool) -> [Attribute] -> [Attribute] filterAttributes p = filter (p . attrType) -- | Add or replace an attribute in a list of attributes. setAttribute :: OID -> [ASN1] -> [Attribute] -> [Attribute] setAttribute oid vals = (:) attr . filterAttributes (/= oid) where attr = Attribute { attrType = oid, attrValues = vals } -- | Find an attribute with the specified attribute and run a parser on the -- attribute value when found. 'Nothing' is returned if the attribute could not -- be found but also when the parse failed. runParseAttribute :: OID -> [Attribute] -> ParseASN1 () a -> Maybe a runParseAttribute oid attrs p = case findAttribute oid attrs of Nothing -> Nothing Just s -> either (const Nothing) Just (runParseASN1 p s) -- | Add or replace an attribute in a list of attributes, using 'ASN1S'. setAttributeASN1S :: OID -> ASN1S -> [Attribute] -> [Attribute] setAttributeASN1S oid g = setAttribute oid (g []) -- Content type contentType :: OID contentType = [1,2,840,113549,1,9,3] -- | Return the value of the @contentType@ attribute. getContentTypeAttr :: [Attribute] -> Maybe ContentType getContentTypeAttr attrs = runParseAttribute contentType attrs $ do OID oid <- getNext withObjectID "content type" oid return -- | Add or replace the @contentType@ attribute in a list of attributes. setContentTypeAttr :: ContentType -> [Attribute] -> [Attribute] setContentTypeAttr ct = setAttributeASN1S contentType (gOID $ getObjectID ct) -- Message digest messageDigest :: OID messageDigest = [1,2,840,113549,1,9,4] -- | Return the value of the @messageDigest@ attribute. getMessageDigestAttr :: [Attribute] -> Maybe ByteString getMessageDigestAttr attrs = runParseAttribute messageDigest attrs $ do OctetString d <- getNext return d -- | Add or replace the @messageDigest@ attribute in a list of attributes. setMessageDigestAttr :: ByteString -> [Attribute] -> [Attribute] setMessageDigestAttr d = setAttributeASN1S messageDigest (gOctetString d) -- Signing time signingTime :: OID signingTime = [1,2,840,113549,1,9,5] -- | Return the value of the @signingTime@ attribute. getSigningTimeAttr :: [Attribute] -> Maybe DateTime getSigningTimeAttr attrs = runParseAttribute signingTime attrs $ do ASN1Time _ t offset <- getNext let validOffset = maybe True (== TimezoneOffset 0) offset if validOffset then return t else fail "getSigningTimeAttr: invalid timezone" -- | Add or replace the @signingTime@ attribute in a list of attributes. setSigningTimeAttr :: DateTime -> [Attribute] -> [Attribute] setSigningTimeAttr t = let normalize val = val { dtTime = (dtTime val) { todNSec = 0 } } offset = Just (TimezoneOffset 0) ty | t >= timeConvert (Date 2050 January 1) = TimeGeneralized | t < timeConvert (Date 1950 January 1) = TimeGeneralized | otherwise = TimeUTC in setAttributeASN1S signingTime (gASN1Time ty (normalize t) offset) -- | Add or replace the @signingTime@ attribute in a list of attributes with the -- current time. This is equivalent to calling 'setSigningTimeAttr' with the -- result of 'dateCurrent'. setSigningTimeAttrCurrent :: MonadIO m => [Attribute] -> m [Attribute] setSigningTimeAttrCurrent attrs = do t <- liftIO dateCurrent return (setSigningTimeAttr t attrs) cryptostore-0.3.1.0/src/Crypto/Store/CMS/AuthEnveloped.hs0000644000000000000000000000731507346545000021331 0ustar0000000000000000-- | -- Module : Crypto.Store.CMS.AuthEnveloped -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RecordWildCards #-} module Crypto.Store.CMS.AuthEnveloped ( AuthEnvelopedData(..) , encodeAuthAttrs ) where import Control.Applicative import Control.Monad import Data.ASN1.Types import Data.ByteArray (convert) import Data.ByteString (ByteString) import Crypto.Cipher.Types import Crypto.Store.ASN1.Generate import Crypto.Store.ASN1.Parse import Crypto.Store.CMS.Algorithms import Crypto.Store.CMS.Attribute import Crypto.Store.CMS.Encrypted import Crypto.Store.CMS.Enveloped import Crypto.Store.CMS.OriginatorInfo import Crypto.Store.CMS.Type import Crypto.Store.CMS.Util -- | Authenticated-enveloped content information. data AuthEnvelopedData content = AuthEnvelopedData { aeOriginatorInfo :: OriginatorInfo -- ^ Optional information about the originator , aeRecipientInfos :: [RecipientInfo] -- ^ Information for recipients, allowing to decrypt the content , aeContentType :: ContentType -- ^ Inner content type , aeContentEncryptionParams :: ASN1ObjectExact AuthContentEncryptionParams -- ^ Encryption algorithm , aeEncryptedContent :: content -- ^ Encrypted content info , aeAuthAttrs :: [Attribute] -- ^ Optional authenticated attributes , aeMAC :: MessageAuthenticationCode -- ^ Message authentication code , aeUnauthAttrs :: [Attribute] -- ^ Optional unauthenticated attributes } deriving (Show,Eq) instance ProduceASN1Object ASN1P (AuthEnvelopedData (Encap EncryptedContent)) where asn1s AuthEnvelopedData{..} = asn1Container Sequence (ver . oi . ris . eci . aa . tag . ua) where ver = gIntVal 0 ris = asn1Container Set (asn1s aeRecipientInfos) eci = encryptedContentInfoASN1S (aeContentType, aeContentEncryptionParams, aeEncryptedContent) aa = attributesASN1S (Container Context 1) aeAuthAttrs tag = gOctetString (convert aeMAC) ua = attributesASN1S (Container Context 2) aeUnauthAttrs oi | aeOriginatorInfo == mempty = id | otherwise = originatorInfoASN1S (Container Context 0) aeOriginatorInfo instance ParseASN1Object [ASN1Event] (AuthEnvelopedData (Encap EncryptedContent)) where parse = onNextContainer Sequence $ do IntVal v <- getNext when (v /= 0) $ throwParseError ("AuthEnvelopedData: parsed invalid version: " ++ show v) oi <- parseOriginatorInfo (Container Context 0) <|> return mempty ris <- onNextContainer Set parse (ct, params, ec) <- parseEncryptedContentInfo aAttrs <- parseAttributes (Container Context 1) OctetString tag <- getNext uAttrs <- parseAttributes (Container Context 2) return AuthEnvelopedData { aeOriginatorInfo = oi , aeContentType = ct , aeRecipientInfos = ris , aeContentEncryptionParams = params , aeEncryptedContent = ec , aeAuthAttrs = aAttrs , aeMAC = AuthTag $ convert tag , aeUnauthAttrs = uAttrs } -- | Return the DER encoding of the attributes as required for AAD. encodeAuthAttrs :: [Attribute] -> ByteString encodeAuthAttrs [] = mempty encodeAuthAttrs l = encodeASN1S $ asn1Container Set (asn1s l) cryptostore-0.3.1.0/src/Crypto/Store/CMS/Authenticated.hs0000644000000000000000000000754307346545000021353 0ustar0000000000000000-- | -- Module : Crypto.Store.CMS.Authenticated -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RecordWildCards #-} module Crypto.Store.CMS.Authenticated ( AuthenticatedData(..) ) where import Control.Applicative import Control.Monad import Data.ASN1.Types import qualified Data.ByteArray as B import Crypto.Cipher.Types import Crypto.Store.ASN1.Generate import Crypto.Store.ASN1.Parse import Crypto.Store.CMS.Algorithms import Crypto.Store.CMS.Attribute import Crypto.Store.CMS.Enveloped import Crypto.Store.CMS.OriginatorInfo import Crypto.Store.CMS.Signed import Crypto.Store.CMS.Type import Crypto.Store.CMS.Util -- | Authenticated content information. data AuthenticatedData content = AuthenticatedData { adOriginatorInfo :: OriginatorInfo -- ^ Optional information about the originator , adRecipientInfos :: [RecipientInfo] -- ^ Information for recipients, allowing to authenticate the content , adMACAlgorithm :: MACAlgorithm -- ^ MAC algorithm , adDigestAlgorithm :: Maybe DigestAlgorithm -- ^ Optional digest algorithm , adContentType :: ContentType -- ^ Inner content type , adEncapsulatedContent :: content -- ^ Encapsulated content , adAuthAttrs :: [Attribute] -- ^ Optional authenticated attributes , adMAC :: MessageAuthenticationCode -- ^ Message authentication code , adUnauthAttrs :: [Attribute] -- ^ Optional unauthenticated attributes } deriving (Show,Eq) instance ProduceASN1Object ASN1P (AuthenticatedData (Encap EncapsulatedContent)) where asn1s AuthenticatedData{..} = asn1Container Sequence (ver . oi . ris . alg . dig . ci . aa . tag . ua) where ver = gIntVal v ris = asn1Container Set (asn1s adRecipientInfos) alg = algorithmASN1S Sequence adMACAlgorithm dig = algorithmMaybeASN1S (Container Context 1) adDigestAlgorithm ci = encapsulatedContentInfoASN1S adContentType adEncapsulatedContent aa = attributesASN1S(Container Context 2) adAuthAttrs tag = gOctetString (B.convert adMAC) ua = attributesASN1S (Container Context 3) adUnauthAttrs oi | adOriginatorInfo == mempty = id | otherwise = originatorInfoASN1S (Container Context 0) adOriginatorInfo v | hasChoiceOther adOriginatorInfo = 3 | otherwise = 0 instance ParseASN1Object [ASN1Event] (AuthenticatedData (Encap EncapsulatedContent)) where parse = onNextContainer Sequence $ do IntVal v <- getNext when (v `notElem` [0, 1, 3]) $ throwParseError ("AuthenticatedData: parsed invalid version: " ++ show v) oi <- parseOriginatorInfo (Container Context 0) <|> return mempty ris <- onNextContainer Set parse alg <- parseAlgorithm Sequence dig <- parseAlgorithmMaybe (Container Context 1) (ct, bs) <- parseEncapsulatedContentInfo aAttrs <- parseAttributes (Container Context 2) OctetString tag <- getNext uAttrs <- parseAttributes (Container Context 3) return AuthenticatedData { adOriginatorInfo = oi , adRecipientInfos = ris , adMACAlgorithm = alg , adDigestAlgorithm = dig , adContentType = ct , adEncapsulatedContent = bs , adAuthAttrs = aAttrs , adMAC = AuthTag $ B.convert tag , adUnauthAttrs = uAttrs } cryptostore-0.3.1.0/src/Crypto/Store/CMS/Digested.hs0000644000000000000000000000636607346545000020323 0ustar0000000000000000-- | -- Module : Crypto.Store.CMS.Digested -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RecordWildCards #-} module Crypto.Store.CMS.Digested ( DigestedData(..) ) where import Control.Monad import Data.ASN1.Types import qualified Data.ByteArray as B import Crypto.Hash hiding (MD5) import Crypto.Store.ASN1.Generate import Crypto.Store.ASN1.Parse import Crypto.Store.CMS.Algorithms import Crypto.Store.CMS.Signed import Crypto.Store.CMS.Type import Crypto.Store.CMS.Util -- | Digested content information. data DigestedData content = forall hashAlg. HashAlgorithm hashAlg => DigestedData { ddDigestAlgorithm :: DigestProxy hashAlg -- ^ Digest algorithm , ddContentType :: ContentType -- ^ Inner content type , ddEncapsulatedContent :: content -- ^ Encapsulated content , ddDigest :: Digest hashAlg -- ^ Digest value } instance Show content => Show (DigestedData content) where showsPrec d DigestedData{..} = showParen (d > 10) $ showString "DigestedData " . showString "{ ddDigestAlgorithm = " . shows ddDigestAlgorithm . showString ", ddContentType = " . shows ddContentType . showString ", ddEncapsulatedContent = " . shows ddEncapsulatedContent . showString ", ddDigest = " . shows ddDigest . showString " }" instance Eq content => Eq (DigestedData content) where DigestedData a1 t1 e1 d1 == DigestedData a2 t2 e2 d2 = DigestAlgorithm a1 == DigestAlgorithm a2 && d1 `B.eq` d2 && t1 == t2 && e1 == e2 instance ASN1Elem e => ProduceASN1Object e (DigestedData (Encap EncapsulatedContent)) where asn1s DigestedData{..} = asn1Container Sequence (ver . alg . ci . dig) where v = if ddContentType == DataType then 0 else 2 d = DigestAlgorithm ddDigestAlgorithm ver = gIntVal v alg = algorithmASN1S Sequence d ci = encapsulatedContentInfoASN1S ddContentType ddEncapsulatedContent dig = gOctetString (B.convert ddDigest) instance Monoid e => ParseASN1Object e (DigestedData (Encap EncapsulatedContent)) where parse = onNextContainer Sequence $ do IntVal v <- getNext when (v /= 0 && v /= 2) $ throwParseError ("DigestedData: parsed invalid version: " ++ show v) alg <- parseAlgorithm Sequence (ct, bs) <- parseEncapsulatedContentInfo OctetString digValue <- getNext case alg of DigestAlgorithm digAlg -> case digestFromByteString digValue of Nothing -> throwParseError "DigestedData: parsed invalid digest" Just d -> return DigestedData { ddDigestAlgorithm = digAlg , ddContentType = ct , ddEncapsulatedContent = bs , ddDigest = d } cryptostore-0.3.1.0/src/Crypto/Store/CMS/Encrypted.hs0000644000000000000000000000733507346545000020525 0ustar0000000000000000-- | -- Module : Crypto.Store.CMS.Encrypted -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RecordWildCards #-} module Crypto.Store.CMS.Encrypted ( EncryptedContent , ContentEncryptionKey , EncryptedData(..) , encryptedContentInfoASN1S , parseEncryptedContentInfo ) where import Control.Applicative import Control.Monad import Data.ASN1.Types import qualified Data.ByteString as B import Crypto.Store.ASN1.Generate import Crypto.Store.ASN1.Parse import Crypto.Store.CMS.Algorithms import Crypto.Store.CMS.Attribute import Crypto.Store.CMS.Type import Crypto.Store.CMS.Util -- | Key used for content encryption. type ContentEncryptionKey = B.ByteString -- | Encrypted content. type EncryptedContent = B.ByteString -- | Encrypted content information. data EncryptedData content = EncryptedData { edContentType :: ContentType -- ^ Inner content type , edContentEncryptionParams :: ContentEncryptionParams -- ^ Encryption algorithm , edEncryptedContent :: content -- ^ Encrypted content info , edUnprotectedAttrs :: [Attribute] -- ^ Optional unprotected attributes } deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e (EncryptedData (Encap EncryptedContent)) where asn1s EncryptedData{..} = asn1Container Sequence (ver . eci . ua) where ver = gIntVal (if null edUnprotectedAttrs then 0 else 2) eci = encryptedContentInfoASN1S (edContentType, edContentEncryptionParams, edEncryptedContent) ua = attributesASN1S (Container Context 1) edUnprotectedAttrs instance Monoid e => ParseASN1Object e (EncryptedData (Encap EncryptedContent)) where parse = onNextContainer Sequence $ do IntVal v <- getNext when (v /= 0 && v /= 2) $ throwParseError ("EncryptedData: parsed invalid version: " ++ show v) (ct, params, ec) <- parseEncryptedContentInfo attrs <- parseAttributes (Container Context 1) return EncryptedData { edContentType = ct , edContentEncryptionParams = params , edEncryptedContent = ec , edUnprotectedAttrs = attrs } -- | Generate ASN.1 for EncryptedContentInfo. encryptedContentInfoASN1S :: (ASN1Elem e, ProduceASN1Object e alg) => (ContentType, alg, Encap EncryptedContent) -> ASN1Stream e encryptedContentInfoASN1S (ct, alg, ec) = asn1Container Sequence (ct' . alg' . ec') where ct' = gOID (getObjectID ct) alg' = asn1s alg ec' = encapsulatedASN1S (Container Context 0) ec encapsulatedASN1S :: ASN1Elem e => ASN1ConstructionType -> Encap EncryptedContent -> ASN1Stream e encapsulatedASN1S _ Detached = id encapsulatedASN1S ty (Attached bs) = asn1Container ty (gOctetString bs) -- | Parse EncryptedContentInfo from ASN.1. parseEncryptedContentInfo :: ParseASN1Object e alg => ParseASN1 e (ContentType, alg, Encap EncryptedContent) parseEncryptedContentInfo = onNextContainer Sequence $ do OID oid <- getNext alg <- parse b <- hasNext ec <- if b then Attached <$> parseEncryptedContent else return Detached withObjectID "content type" oid $ \ct -> return (ct, alg, ec) where parseEncryptedContent = parseWrapped <|> parsePrimitive parseWrapped = onNextContainer (Container Context 0) parseOctetStrings parsePrimitive = do Other Context 0 bs <- getNext; return bs cryptostore-0.3.1.0/src/Crypto/Store/CMS/Enveloped.hs0000644000000000000000000006204707346545000020512 0ustar0000000000000000-- | -- Module : Crypto.Store.CMS.Enveloped -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RecordWildCards #-} module Crypto.Store.CMS.Enveloped ( EncryptedKey , UserKeyingMaterial , RecipientInfo(..) , EnvelopedData(..) , ProducerOfRI , ConsumerOfRI -- * Key Transport recipients , KTRecipientInfo(..) , RecipientIdentifier(..) , IssuerAndSerialNumber(..) , forKeyTransRecipient , withRecipientKeyTrans -- * Key Agreement recipients , KARecipientInfo(..) , OriginatorIdentifierOrKey(..) , OriginatorPublicKey , RecipientEncryptedKey(..) , KeyAgreeRecipientIdentifier(..) , forKeyAgreeRecipient , withRecipientKeyAgree -- * Key Encryption Key recipients , KeyEncryptionKey , KEKRecipientInfo(..) , KeyIdentifier(..) , OtherKeyAttribute(..) , forKeyRecipient , withRecipientKey -- * Password recipients , Password , PasswordRecipientInfo(..) , forPasswordRecipient , withRecipientPassword ) where import Control.Applicative import Control.Monad import Data.ASN1.BitArray import Data.ASN1.Types import Data.ByteString (ByteString) import Data.List (find) import Data.Maybe (fromMaybe) import Data.X509 import Time.Types import Crypto.Random (MonadRandom) import Crypto.Store.ASN1.Generate import Crypto.Store.ASN1.Parse import Crypto.Store.CMS.Algorithms import Crypto.Store.CMS.Attribute import Crypto.Store.CMS.Encrypted import Crypto.Store.CMS.OriginatorInfo import Crypto.Store.CMS.Type import Crypto.Store.CMS.Util import Crypto.Store.Error -- | Encrypted key. type EncryptedKey = ByteString -- | User keying material. type UserKeyingMaterial = ByteString -- | Key used for key encryption. type KeyEncryptionKey = ByteString -- | A password stored as a sequence of UTF-8 bytes. -- -- Some key-derivation functions add restrictions to what characters -- are supported. -- -- Beware: 'Data.String.fromString' truncates multi-byte characters. -- If the string may contain non-ASCII characters, prefer instead -- @'Crypto.Store.PKCS5.fromProtectionPassword' . 'Data.String.fromString'@. type Password = ByteString -- | Union type related to identification of the recipient. data RecipientIdentifier = RecipientIASN IssuerAndSerialNumber -- ^ Issuer and Serial Number | RecipientSKI ByteString -- ^ Subject Key Identifier deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e RecipientIdentifier where asn1s (RecipientIASN iasn) = asn1s iasn asn1s (RecipientSKI ski) = asn1Container (Container Context 0) (gOctetString ski) instance Monoid e => ParseASN1Object e RecipientIdentifier where parse = parseIASN <|> parseSKI where parseIASN = RecipientIASN <$> parse parseSKI = RecipientSKI <$> onNextContainer (Container Context 0) parseOctetStringPrim getKTVersion :: RecipientIdentifier -> Integer getKTVersion (RecipientIASN _) = 0 getKTVersion (RecipientSKI _) = 2 -- | Identification of a certificate using the issuer DN and serial number. data IssuerAndSerialNumber = IssuerAndSerialNumber { iasnIssuer :: DistinguishedName -- ^ Distinguished name of the certificate issuer , iasnSerial :: Integer -- ^ Issuer-specific certificate serial number } deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e IssuerAndSerialNumber where asn1s IssuerAndSerialNumber{..} = asn1Container Sequence (asn1s iasnIssuer . gIntVal iasnSerial) instance Monoid e => ParseASN1Object e IssuerAndSerialNumber where parse = onNextContainer Sequence $ do i <- parse IntVal s <- getNext return IssuerAndSerialNumber { iasnIssuer = i , iasnSerial = s } idEcPublicKey :: OID idEcPublicKey = [1,2,840,10045,2,1] -- | Originator public key used for key-agreement. Contrary to 'PubKey' the -- domain parameters are not used and may be left empty. data OriginatorPublicKey = OriginatorPublicKeyEC [ASN1] BitArray deriving (Show,Eq) originatorPublicKeyASN1S :: ASN1Elem e => ASN1ConstructionType -> OriginatorPublicKey -> ASN1Stream e originatorPublicKeyASN1S ty (OriginatorPublicKeyEC asn1 ba) = asn1Container ty (alg . gBitString ba) where alg = asn1Container Sequence (gOID idEcPublicKey . gMany asn1) parseOriginatorPublicKey :: Monoid e => ASN1ConstructionType -> ParseASN1 e OriginatorPublicKey parseOriginatorPublicKey ty = onNextContainer ty $ do asn1 <- onNextContainer Sequence $ do OID oid <- getNext guard (oid == idEcPublicKey) getMany getNext BitString ba <- getNext return (OriginatorPublicKeyEC asn1 ba) -- | Union type related to identification of the originator. data OriginatorIdentifierOrKey = OriginatorIASN IssuerAndSerialNumber -- ^ Issuer and Serial Number | OriginatorSKI ByteString -- ^ Subject Key Identifier | OriginatorPublic OriginatorPublicKey -- ^ Anonymous public key deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e OriginatorIdentifierOrKey where asn1s (OriginatorIASN iasn) = asn1s iasn asn1s (OriginatorSKI ski) = asn1Container (Container Context 0) (gOctetString ski) asn1s (OriginatorPublic pub) = originatorPublicKeyASN1S (Container Context 1) pub instance Monoid e => ParseASN1Object e OriginatorIdentifierOrKey where parse = parseIASN <|> parseSKI <|> parsePublic where parseIASN = OriginatorIASN <$> parse parseSKI = OriginatorSKI <$> onNextContainer (Container Context 0) parseOctetStringPrim parsePublic = OriginatorPublic <$> parseOriginatorPublicKey (Container Context 1) -- | Union type related to identification of a key-agreement recipient. data KeyAgreeRecipientIdentifier = KeyAgreeRecipientIASN IssuerAndSerialNumber -- ^ Issuer and Serial Number | KeyAgreeRecipientKI KeyIdentifier -- ^ Key identifier deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e KeyAgreeRecipientIdentifier where asn1s (KeyAgreeRecipientIASN iasn) = asn1s iasn asn1s (KeyAgreeRecipientKI ki) = asn1Container (Container Context 0) (asn1s ki) instance Monoid e => ParseASN1Object e KeyAgreeRecipientIdentifier where parse = parseIASN <|> parseKI where parseIASN = KeyAgreeRecipientIASN <$> parse parseKI = KeyAgreeRecipientKI <$> onNextContainer (Container Context 0) parse -- | Encrypted key for a recipient in a key-agreement RI. data RecipientEncryptedKey = RecipientEncryptedKey { rekRid :: KeyAgreeRecipientIdentifier -- ^ identifier of recipient , rekEncryptedKey :: EncryptedKey -- ^ encrypted content-encryption key } deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e RecipientEncryptedKey where asn1s RecipientEncryptedKey{..} = asn1Container Sequence (rid . ek) where rid = asn1s rekRid ek = gOctetString rekEncryptedKey instance Monoid e => ParseASN1Object e RecipientEncryptedKey where parse = onNextContainer Sequence $ do rid <- parse OctetString ek <- getNext return RecipientEncryptedKey { rekRid = rid, rekEncryptedKey = ek } findRecipientEncryptedKey :: SignedCertificate -> [RecipientEncryptedKey] -> Maybe EncryptedKey findRecipientEncryptedKey cert list = rekEncryptedKey <$> find fn list where c = signedObject (getSigned cert) matchIASN iasn = (iasnIssuer iasn, iasnSerial iasn) == (certIssuerDN c, certSerial c) matchSKI ski = case extensionGet (certExtensions c) of Just (ExtSubjectKeyId idBs) -> idBs == ski Nothing -> False fn rek = case rekRid rek of KeyAgreeRecipientIASN iasn -> matchIASN iasn KeyAgreeRecipientKI ki -> matchSKI (keyIdentifier ki) -- | Additional information in a 'KeyIdentifier'. data OtherKeyAttribute = OtherKeyAttribute { keyAttrId :: OID -- ^ attribute identifier , keyAttr :: [ASN1] -- ^ attribute value } deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e OtherKeyAttribute where asn1s OtherKeyAttribute{..} = asn1Container Sequence (attrId . attr) where attrId = gOID keyAttrId attr = gMany keyAttr instance Monoid e => ParseASN1Object e OtherKeyAttribute where parse = onNextContainer Sequence $ do OID attrId <- getNext attr <- getMany getNext return OtherKeyAttribute { keyAttrId = attrId, keyAttr = attr } -- | Key identifier and optional attributes. data KeyIdentifier = KeyIdentifier { keyIdentifier :: ByteString -- ^ identifier of the key , keyDate :: Maybe DateTime -- ^ optional timestamp , keyOther :: Maybe OtherKeyAttribute -- ^ optional information } deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e KeyIdentifier where asn1s KeyIdentifier{..} = asn1Container Sequence (keyId . date . other) where keyId = gOctetString keyIdentifier date = optASN1S keyDate $ \v -> gASN1Time TimeGeneralized v Nothing other = optASN1S keyOther asn1s instance Monoid e => ParseASN1Object e KeyIdentifier where parse = onNextContainer Sequence $ do OctetString keyId <- getNext date <- getNextMaybe dateTimeOrNothing b <- hasNext other <- if b then Just <$> parse else return Nothing return KeyIdentifier { keyIdentifier = keyId , keyDate = date , keyOther = other } -- | Recipient using key transport. data KTRecipientInfo = KTRecipientInfo { ktRid :: RecipientIdentifier -- ^ identifier of recipient , ktKeyTransportParams :: KeyTransportParams -- ^ key transport algorithm , ktEncryptedKey :: EncryptedKey -- ^ encrypted content-encryption key } deriving (Show,Eq) -- | Recipient using key agreement. data KARecipientInfo = KARecipientInfo { kaOriginator :: OriginatorIdentifierOrKey -- ^ identifier of orginator or anonymous key , kaUkm :: Maybe UserKeyingMaterial -- ^ user keying material , kaKeyAgreementParams :: KeyAgreementParams -- ^ key agreement algorithm , kaRecipientEncryptedKeys :: [RecipientEncryptedKey] -- ^ encrypted content-encryption key for one or multiple recipients } deriving (Show,Eq) -- | Recipient using key encryption. data KEKRecipientInfo = KEKRecipientInfo { kekId :: KeyIdentifier -- ^ identifier of key encryption key , kekKeyEncryptionParams :: KeyEncryptionParams -- ^ key encryption algorithm , kekEncryptedKey :: EncryptedKey -- ^ encrypted content-encryption key } deriving (Show,Eq) -- | Recipient using password-based protection. data PasswordRecipientInfo = PasswordRecipientInfo { priKeyDerivationFunc :: KeyDerivationFunc -- ^ function to derive key , priKeyEncryptionParams :: KeyEncryptionParams -- ^ key encryption algorithm , priEncryptedKey :: EncryptedKey -- ^ encrypted content-encryption key } deriving (Show,Eq) -- | Information for a recipient of an 'EnvelopedData'. An element contains -- the content-encryption key in encrypted form. data RecipientInfo = KTRI KTRecipientInfo -- ^ Recipient using key transport | KARI KARecipientInfo -- ^ Recipient using key agreement | KEKRI KEKRecipientInfo -- ^ Recipient using key encryption | PasswordRI PasswordRecipientInfo -- ^ Recipient using password-based protection deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e RecipientInfo where asn1s (KTRI KTRecipientInfo{..}) = asn1Container Sequence (ver . rid . ktp . ek) where ver = gIntVal (getKTVersion ktRid) rid = asn1s ktRid ktp = algorithmASN1S Sequence ktKeyTransportParams ek = gOctetString ktEncryptedKey asn1s (KARI KARecipientInfo{..}) = asn1Container (Container Context 1) (ver . ori . ukm . kap . reks) where ver = gIntVal 3 ori = asn1Container (Container Context 0) (asn1s kaOriginator) kap = algorithmASN1S Sequence kaKeyAgreementParams reks = asn1Container Sequence (asn1s kaRecipientEncryptedKeys) ukm = case kaUkm of Nothing -> id Just bs -> asn1Container (Container Context 1) (gOctetString bs) asn1s (KEKRI KEKRecipientInfo{..}) = asn1Container (Container Context 2) (ver . kid . kep . ek) where ver = gIntVal 4 kid = asn1s kekId kep = algorithmASN1S Sequence kekKeyEncryptionParams ek = gOctetString kekEncryptedKey asn1s (PasswordRI PasswordRecipientInfo{..}) = asn1Container (Container Context 3) (ver . kdf . kep . ek) where ver = gIntVal 0 kdf = algorithmASN1S (Container Context 0) priKeyDerivationFunc kep = algorithmASN1S Sequence priKeyEncryptionParams ek = gOctetString priEncryptedKey instance Monoid e => ParseASN1Object e RecipientInfo where parse = do c <- onNextContainerMaybe Sequence parseKT `orElse` onNextContainerMaybe (Container Context 1) parseKA `orElse` onNextContainerMaybe (Container Context 2) parseKEK `orElse` onNextContainerMaybe (Container Context 3) parsePassword case c of Just val -> return val Nothing -> throwParseError "RecipientInfo: unable to parse" where parseKT = KTRI <$> do IntVal v <- getNext when (v `notElem` [0, 2]) $ throwParseError ("RecipientInfo: parsed invalid KT version: " ++ show v) rid <- parse ktp <- parseAlgorithm Sequence OctetString ek <- getNext return KTRecipientInfo { ktRid = rid , ktKeyTransportParams = ktp , ktEncryptedKey = ek } parseKA = KARI <$> do IntVal 3 <- getNext ori <- onNextContainer (Container Context 0) parse ukm <- onNextContainerMaybe (Container Context 1) $ do { OctetString bs <- getNext; return bs } kap <- parseAlgorithm Sequence reks <- onNextContainer Sequence parse return KARecipientInfo { kaOriginator = ori , kaUkm = ukm , kaKeyAgreementParams = kap , kaRecipientEncryptedKeys = reks } parseKEK = KEKRI <$> do IntVal 4 <- getNext kid <- parse kep <- parseAlgorithm Sequence OctetString ek <- getNext return KEKRecipientInfo { kekId = kid , kekKeyEncryptionParams = kep , kekEncryptedKey = ek } parsePassword = PasswordRI <$> do IntVal 0 <- getNext kdf <- parseAlgorithm (Container Context 0) kep <- parseAlgorithm Sequence OctetString ek <- getNext return PasswordRecipientInfo { priKeyDerivationFunc = kdf , priKeyEncryptionParams = kep , priEncryptedKey = ek } isVersion0 :: RecipientInfo -> Bool isVersion0 (KTRI x) = getKTVersion (ktRid x) == 0 isVersion0 (KARI _) = False -- because version is always 3 isVersion0 (KEKRI _) = False -- because version is always 4 isVersion0 (PasswordRI _) = True -- because version is always 0 isPwriOri :: RecipientInfo -> Bool isPwriOri (KTRI _) = False isPwriOri (KARI _) = False isPwriOri (KEKRI _) = False isPwriOri (PasswordRI _) = True -- | Enveloped content information. data EnvelopedData content = EnvelopedData { evOriginatorInfo :: OriginatorInfo -- ^ Optional information about the originator , evRecipientInfos :: [RecipientInfo] -- ^ Information for recipients, allowing to decrypt the content , evContentType :: ContentType -- ^ Inner content type , evContentEncryptionParams :: ContentEncryptionParams -- ^ Encryption algorithm , evEncryptedContent :: content -- ^ Encrypted content info , evUnprotectedAttrs :: [Attribute] -- ^ Optional unprotected attributes } deriving (Show,Eq) instance ProduceASN1Object ASN1P (EnvelopedData (Encap EncryptedContent)) where asn1s EnvelopedData{..} = asn1Container Sequence (ver . oi . ris . eci . ua) where ver = gIntVal v ris = asn1Container Set (asn1s evRecipientInfos) eci = encryptedContentInfoASN1S (evContentType, evContentEncryptionParams, evEncryptedContent) ua = attributesASN1S (Container Context 1) evUnprotectedAttrs oi | evOriginatorInfo == mempty = id | otherwise = originatorInfoASN1S (Container Context 0) evOriginatorInfo v | hasChoiceOther evOriginatorInfo = 4 | any isPwriOri evRecipientInfos = 3 | evOriginatorInfo /= mempty = 2 | not (null evUnprotectedAttrs) = 2 | all isVersion0 evRecipientInfos = 0 | otherwise = 2 instance ParseASN1Object [ASN1Event] (EnvelopedData (Encap EncryptedContent)) where parse = onNextContainer Sequence $ do IntVal v <- getNext when (v > 4) $ throwParseError ("EnvelopedData: parsed invalid version: " ++ show v) oi <- parseOriginatorInfo (Container Context 0) <|> return mempty ris <- onNextContainer Set parse (ct, params, ec) <- parseEncryptedContentInfo attrs <- parseAttributes (Container Context 1) return EnvelopedData { evOriginatorInfo = oi , evRecipientInfos = ris , evContentType = ct , evContentEncryptionParams = params , evEncryptedContent = ec , evUnprotectedAttrs = attrs } -- | Function able to produce a 'RecipientInfo'. type ProducerOfRI m = ContentEncryptionKey -> m (Either StoreError RecipientInfo) -- | Function able to consume a 'RecipientInfo'. type ConsumerOfRI m = RecipientInfo -> m (Either StoreError ContentEncryptionKey) -- | Generate a Key Transport recipient from a certificate and -- desired algorithm. The recipient will contain certificate identifier. -- -- This function can be used as parameter to 'Crypto.Store.CMS.envelopData'. forKeyTransRecipient :: MonadRandom m => SignedCertificate -> KeyTransportParams -> ProducerOfRI m forKeyTransRecipient cert params inkey = do ek <- transportEncrypt params (certPubKey obj) inkey return (KTRI . build <$> ek) where obj = signedObject (getSigned cert) isn = IssuerAndSerialNumber (certIssuerDN obj) (certSerial obj) build ek = KTRecipientInfo { ktRid = RecipientIASN isn , ktKeyTransportParams = params , ktEncryptedKey = ek } -- | Use a Key Transport recipient, knowing the private key. -- -- This function can be used as parameter to -- 'Crypto.Store.CMS.openEnvelopedData'. withRecipientKeyTrans :: MonadRandom m => PrivKey -> ConsumerOfRI m withRecipientKeyTrans privKey (KTRI KTRecipientInfo{..}) = transportDecrypt ktKeyTransportParams privKey ktEncryptedKey withRecipientKeyTrans _ _ = pure (Left RecipientTypeMismatch) -- | Generate a Key Agreement recipient from a certificate and -- desired algorithm. The recipient info will contain an ephemeral public key. -- -- This function can be used as parameter to 'Crypto.Store.CMS.envelopData'. -- -- To avoid decreasing the security strength, Key Encryption parameters should -- use a key size equal or greater than the content encryption key. forKeyAgreeRecipient :: MonadRandom m => SignedCertificate -> KeyAgreementParams -> ProducerOfRI m forKeyAgreeRecipient cert params inkey = do ephemeral <- ecdhGenerate (certPubKey obj) case ephemeral of Right pair -> do let pt = ecdhPublic pair aPub = OriginatorPublicKeyEC [] (toBitArray pt 0) ek <- ecdhEncrypt params Nothing pair inkey return (KARI . build aPub <$> ek) Left err -> return $ Left err where obj = signedObject (getSigned cert) isn = IssuerAndSerialNumber (certIssuerDN obj) (certSerial obj) makeREK ek = RecipientEncryptedKey { rekRid = KeyAgreeRecipientIASN isn , rekEncryptedKey = ek } build aPub ek = KARecipientInfo { kaOriginator = OriginatorPublic aPub , kaUkm = Nothing , kaKeyAgreementParams = params , kaRecipientEncryptedKeys = [ makeREK ek ] } -- | Use a Key Agreement recipient, knowing the recipient private key. The -- recipient certificate is also required to locate which encrypted key to use. -- -- This function can be used as parameter to -- 'Crypto.Store.CMS.openEnvelopedData'. withRecipientKeyAgree :: MonadRandom m => PrivKey -> SignedCertificate -> ConsumerOfRI m withRecipientKeyAgree priv cert (KARI KARecipientInfo{..}) = case kaOriginator of OriginatorPublic (OriginatorPublicKeyEC _ ba) -> case findRecipientEncryptedKey cert kaRecipientEncryptedKeys of Nothing -> pure (Left RecipientKeyNotFound) Just ek -> let pub = bitArrayGetData ba in pure (ecdhDecrypt kaKeyAgreementParams kaUkm priv pub ek) _ -> pure (Left UnsupportedOriginatorFormat) withRecipientKeyAgree _ _ _ = pure (Left RecipientTypeMismatch) -- | Generate a Key Encryption Key recipient from a key encryption key and -- desired algorithm. The recipient may identify the KEK that was used with -- the supplied identifier. -- -- This function can be used as parameter to 'Crypto.Store.CMS.envelopData'. -- -- To avoid decreasing the security strength, Key Encryption parameters should -- use a key size equal or greater than the content encryption key. forKeyRecipient :: MonadRandom m => KeyEncryptionKey -> KeyIdentifier -> KeyEncryptionParams -> ProducerOfRI m forKeyRecipient key kid params inkey = do ek <- keyEncrypt key params inkey return (KEKRI . build <$> ek) where build ek = KEKRecipientInfo { kekId = kid , kekKeyEncryptionParams = params , kekEncryptedKey = ek } -- | Use a Key Encryption Key recipient, knowing the key encryption key. -- -- This function can be used as parameter to -- 'Crypto.Store.CMS.openEnvelopedData'. withRecipientKey :: Applicative f => KeyEncryptionKey -> ConsumerOfRI f withRecipientKey key (KEKRI KEKRecipientInfo{..}) = pure (keyDecrypt key kekKeyEncryptionParams kekEncryptedKey) withRecipientKey _ _ = pure (Left RecipientTypeMismatch) -- | Generate a password recipient from a password. -- -- This function can be used as parameter to 'Crypto.Store.CMS.envelopData'. forPasswordRecipient :: MonadRandom m => Password -> KeyDerivationFunc -> KeyEncryptionParams -> ProducerOfRI m forPasswordRecipient pwd kdf params inkey = do ek <- keyEncrypt derived params inkey return (PasswordRI . build <$> ek) where derived = kdfDerive kdf len pwd :: EncryptedKey len = fromMaybe (getMaximumKeySize params) (kdfKeyLength kdf) build ek = PasswordRecipientInfo { priKeyDerivationFunc = kdf , priKeyEncryptionParams = params , priEncryptedKey = ek } -- | Use a password recipient, knowing the password. -- -- This function can be used as parameter to -- 'Crypto.Store.CMS.openEnvelopedData'. withRecipientPassword :: Applicative f => Password -> ConsumerOfRI f withRecipientPassword pwd (PasswordRI PasswordRecipientInfo{..}) = pure (keyDecrypt derived priKeyEncryptionParams priEncryptedKey) where derived = kdfDerive priKeyDerivationFunc len pwd :: EncryptedKey len = fromMaybe (getMaximumKeySize priKeyEncryptionParams) (kdfKeyLength priKeyDerivationFunc) withRecipientPassword _ _ = pure (Left RecipientTypeMismatch) cryptostore-0.3.1.0/src/Crypto/Store/CMS/Info.hs0000644000000000000000000001713207346545000017457 0ustar0000000000000000-- | -- Module : Crypto.Store.CMS.Info -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- CMS content information. {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} module Crypto.Store.CMS.Info ( ContentInfo(..) , getContentType , Encapsulates , isAttached , fromAttached , toAttachedCI , isDetached , fromDetached , toDetachedCI ) where import Control.Monad.Fail (MonadFail) import Data.ASN1.Types import Data.ByteString (ByteString) import Data.Functor.Identity import Data.Maybe (isJust, isNothing) import Crypto.Store.ASN1.Generate import Crypto.Store.ASN1.Parse import Crypto.Store.CMS.Authenticated import Crypto.Store.CMS.AuthEnveloped import Crypto.Store.CMS.Digested import Crypto.Store.CMS.Encrypted import Crypto.Store.CMS.Enveloped import Crypto.Store.CMS.Signed import Crypto.Store.CMS.Type import Crypto.Store.CMS.Util -- | Get the type of a content info. getContentType :: ContentInfo -> ContentType getContentType (DataCI _) = DataType getContentType (SignedDataCI _) = SignedDataType getContentType (EnvelopedDataCI _) = EnvelopedDataType getContentType (DigestedDataCI _) = DigestedDataType getContentType (EncryptedDataCI _) = EncryptedDataType getContentType (AuthenticatedDataCI _) = AuthenticatedDataType getContentType (AuthEnvelopedDataCI _) = AuthEnvelopedDataType -- ContentInfo -- | CMS content information. data ContentInfo = DataCI ByteString -- ^ Arbitrary octet string | SignedDataCI (SignedData (Encap EncapsulatedContent)) -- ^ Signed content info | EnvelopedDataCI (EnvelopedData (Encap EncryptedContent)) -- ^ Enveloped content info | DigestedDataCI (DigestedData (Encap EncapsulatedContent)) -- ^ Content info with associated digest | EncryptedDataCI (EncryptedData (Encap EncryptedContent)) -- ^ Encrypted content info | AuthenticatedDataCI (AuthenticatedData (Encap EncapsulatedContent)) -- ^ Authenticatedcontent info | AuthEnvelopedDataCI (AuthEnvelopedData (Encap EncryptedContent)) -- ^ Authenticated-enveloped content info deriving (Show,Eq) instance ProduceASN1Object ASN1P ContentInfo where asn1s ci = asn1Container Sequence (oid . cont) where oid = gOID $ getObjectID $ getContentType ci cont = asn1Container (Container Context 0) inner inner = case ci of DataCI bs -> dataASN1S bs SignedDataCI ed -> asn1s ed EnvelopedDataCI ed -> asn1s ed DigestedDataCI dd -> asn1s dd EncryptedDataCI ed -> asn1s ed AuthenticatedDataCI ad -> asn1s ad AuthEnvelopedDataCI ae -> asn1s ae instance ParseASN1Object [ASN1Event] ContentInfo where parse = onNextContainer Sequence $ do OID oid <- getNext withObjectID "content type" oid $ \ct -> onNextContainer (Container Context 0) (parseInner ct) where parseInner DataType = DataCI <$> parseData parseInner SignedDataType = SignedDataCI <$> parse parseInner EnvelopedDataType = EnvelopedDataCI <$> parse parseInner DigestedDataType = DigestedDataCI <$> parse parseInner EncryptedDataType = EncryptedDataCI <$> parse parseInner AuthenticatedDataType = AuthenticatedDataCI <$> parse parseInner AuthEnvelopedDataType = AuthEnvelopedDataCI <$> parse -- Data dataASN1S :: ASN1Elem e => ByteString -> ASN1Stream e dataASN1S = gOctetString parseData :: Monoid e => ParseASN1 e ByteString parseData = parseOctetString -- Encapsulation -- | Class of data structures with inner content that may be stored externally. -- This class has instances for each CMS content type containing other -- encapsulated or encrypted content info. -- -- Functions 'fromAttached' and 'fromDetached' are used to introspect -- encapsulation state (attached or detached), and recover a data structure with -- actionable content. -- -- Functions 'toAttachedCI' and 'toDetachedCI' are needed to decide about the -- outer encapsulation state and build a 'ContentInfo'. class Encapsulates struct where lens :: Functor f => (a -> f b) -> struct a -> f (struct b) toCI :: struct (Encap ByteString) -> ContentInfo instance Encapsulates SignedData where lens f s = let g a = s { sdEncapsulatedContent = a } in fmap g (f $ sdEncapsulatedContent s) toCI = SignedDataCI instance Encapsulates EnvelopedData where lens f s = let g a = s { evEncryptedContent = a } in fmap g (f $ evEncryptedContent s) toCI = EnvelopedDataCI instance Encapsulates DigestedData where lens f s = let g a = s { ddEncapsulatedContent = a } in fmap g (f $ ddEncapsulatedContent s) toCI = DigestedDataCI instance Encapsulates EncryptedData where lens f s = let g a = s { edEncryptedContent = a } in fmap g (f $ edEncryptedContent s) toCI = EncryptedDataCI instance Encapsulates AuthenticatedData where lens f s = let g a = s { adEncapsulatedContent = a } in fmap g (f $ adEncapsulatedContent s) toCI = AuthenticatedDataCI instance Encapsulates AuthEnvelopedData where lens f s = let g a = s { aeEncryptedContent = a } in fmap g (f $ aeEncryptedContent s) toCI = AuthEnvelopedDataCI -- | Return 'True' when the encapsulated content is attached. isAttached :: Encapsulates struct => struct (Encap a) -> Bool isAttached = isJust . fromAttached -- | Unwrap the encapsulation, assuming the inner content is inside the data -- structure. The monadic computation fails if the content was detached. fromAttached :: (MonadFail m, Encapsulates struct) => struct (Encap a) -> m (struct a) fromAttached = lens (fromEncap err return) where err = fail "fromAttached: detached" -- | Keep the content inside the data structure. toAttached :: Encapsulates struct => struct a -> struct (Encap a) toAttached = runIdentity . lens (Identity . Attached) -- | Transform the data structure into a content info, keeping the encapsulated -- content attached. May be applied to structures with 'EncapsulatedContent' or -- 'EncryptedContent'. toAttachedCI :: Encapsulates struct => struct ByteString -> ContentInfo toAttachedCI = toCI . toAttached -- | Return 'True' when the encapsulated content is detached. isDetached :: Encapsulates struct => struct (Encap a) -> Bool isDetached = isNothing . fromAttached -- | Recover the original data structure from a detached encapsulation and the -- external content. The monadic computation fails if the content was attached. fromDetached :: (MonadFail m, Encapsulates struct) => b -> struct (Encap a) -> m (struct b) fromDetached c = lens (fromEncap (return c) err) where err _ = fail "fromDetached: attached" -- | Remove the content from the data structure to store it externally. toDetached :: Encapsulates struct => struct a -> (a, struct (Encap a)) toDetached = let f a = (a, Detached) in lens f -- | Transform the data structure into a content info, detaching the -- encapsulated content. May be applied to structures with -- 'EncapsulatedContent' or 'EncryptedContent'. toDetachedCI :: Encapsulates struct => struct ByteString -> (ByteString, ContentInfo) toDetachedCI = fmap toCI . toDetached cryptostore-0.3.1.0/src/Crypto/Store/CMS/OriginatorInfo.hs0000644000000000000000000001514107346545000021513 0ustar0000000000000000-- | -- Module : Crypto.Store.CMS.OriginatorInfo -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RecordWildCards #-} module Crypto.Store.CMS.OriginatorInfo ( OriginatorInfo(..) , CertificateChoice(..) , OtherCertificateFormat(..) , RevocationInfoChoice(..) , OtherRevocationInfoFormat(..) , originatorInfoASN1S , parseOriginatorInfo , hasChoiceOther ) where import Control.Applicative import Data.ASN1.Types import Data.Maybe (fromMaybe) import Data.Semigroup import Data.X509 import Crypto.Store.ASN1.Generate import Crypto.Store.ASN1.Parse import Crypto.Store.CMS.Util -- | Data types where choice "other" is available. class HasChoiceOther a where -- | Return true when choice "other" is selected. hasChoiceOther :: a -> Bool instance (HasChoiceOther a, Foldable f) => HasChoiceOther (f a) where hasChoiceOther = any hasChoiceOther -- | Information about the originator of the content info, to be used when -- a key management algorithm requires this information. data OriginatorInfo = OriginatorInfo { originatorCerts :: [CertificateChoice] -- ^ The collection of certificates , originatorCRLs :: [RevocationInfoChoice] -- ^ The collection of CRLs } deriving (Show,Eq) instance Semigroup OriginatorInfo where OriginatorInfo a b <> OriginatorInfo c d = OriginatorInfo (a <> c) (b <> d) instance Monoid OriginatorInfo where mempty = OriginatorInfo [] [] mappend = (<>) instance HasChoiceOther OriginatorInfo where hasChoiceOther OriginatorInfo{..} = hasChoiceOther originatorCerts || hasChoiceOther originatorCRLs instance ProduceASN1Object ASN1P OriginatorInfo where asn1s = originatorInfoASN1S Sequence instance ParseASN1Object [ASN1Event] OriginatorInfo where parse = parseOriginatorInfo Sequence -- | Generate ASN.1 with the specified constructed type for the originator -- information. originatorInfoASN1S :: ASN1ConstructionType -> OriginatorInfo -> ASN1PS originatorInfoASN1S ty OriginatorInfo{..} = asn1Container ty $ gen 0 originatorCerts . gen 1 originatorCRLs where gen tag list | null list = id | otherwise = asn1Container (Container Context tag) (asn1s list) -- | Parse originator information with the specified constructed type. parseOriginatorInfo :: ASN1ConstructionType -> ParseASN1 [ASN1Event] OriginatorInfo parseOriginatorInfo ty = onNextContainer ty $ do certs <- parseOptList 0 crls <- parseOptList 1 return OriginatorInfo { originatorCerts = certs , originatorCRLs = crls } where parseOptList tag = fromMaybe [] <$> onNextContainerMaybe (Container Context tag) parse -- | Union type related to certificate formats. data CertificateChoice = CertificateCertificate SignedCertificate -- ^ X.509 certificate | CertificateOther OtherCertificateFormat -- ^ Other format deriving (Show,Eq) instance HasChoiceOther CertificateChoice where hasChoiceOther (CertificateOther _) = True hasChoiceOther _ = False instance ProduceASN1Object ASN1P CertificateChoice where asn1s (CertificateCertificate cert) = asn1s cert asn1s (CertificateOther other) = otherCertificateFormatASN1PS (Container Context 3) other instance ParseASN1Object [ASN1Event] CertificateChoice where parse = parseMain <|> parseOther where parseMain = CertificateCertificate <$> parse parseOther = CertificateOther <$> parseOtherCertificateFormat (Container Context 3) -- | Union type related to revocation info formats. data RevocationInfoChoice = RevocationInfoCRL SignedCRL -- ^ A CRL, ARL, Delta CRL, or an ACRL | RevocationInfoOther OtherRevocationInfoFormat -- ^ Other format deriving (Show,Eq) instance HasChoiceOther RevocationInfoChoice where hasChoiceOther (RevocationInfoOther _) = True hasChoiceOther _ = False instance ProduceASN1Object ASN1P RevocationInfoChoice where asn1s (RevocationInfoCRL crl) = asn1s crl asn1s (RevocationInfoOther other) = otherRevocationInfoFormatASN1PS (Container Context 1) other instance ParseASN1Object [ASN1Event] RevocationInfoChoice where parse = parseMain <|> parseOther where parseMain = RevocationInfoCRL <$> parse parseOther = RevocationInfoOther <$> parseOtherRevocationInfoFormat (Container Context 1) -- | Certificate information in a format not supported natively. data OtherCertificateFormat = OtherCertificateFormat { otherCertFormat :: OID -- ^ Format identifier , otherCertValues :: [ASN1] -- ^ ASN.1 values using this format } deriving (Show,Eq) otherCertificateFormatASN1PS :: ASN1Elem e => ASN1ConstructionType -> OtherCertificateFormat -> ASN1Stream e otherCertificateFormatASN1PS ty OtherCertificateFormat{..} = asn1Container ty (f . v) where f = gOID otherCertFormat v = gMany otherCertValues parseOtherCertificateFormat :: Monoid e => ASN1ConstructionType -> ParseASN1 e OtherCertificateFormat parseOtherCertificateFormat ty = onNextContainer ty $ do OID f <- getNext v <- getMany getNext return OtherCertificateFormat { otherCertFormat = f , otherCertValues = v } -- | Revocation information in a format not supported natively. data OtherRevocationInfoFormat = OtherRevocationInfoFormat { otherRevInfoFormat :: OID -- ^ Format identifier , otherRevInfoValues :: [ASN1] -- ^ ASN.1 values using this format } deriving (Show,Eq) otherRevocationInfoFormatASN1PS :: ASN1Elem e => ASN1ConstructionType -> OtherRevocationInfoFormat -> ASN1Stream e otherRevocationInfoFormatASN1PS ty OtherRevocationInfoFormat{..} = asn1Container ty (f . v) where f = gOID otherRevInfoFormat v = gMany otherRevInfoValues parseOtherRevocationInfoFormat :: Monoid e => ASN1ConstructionType -> ParseASN1 e OtherRevocationInfoFormat parseOtherRevocationInfoFormat ty = onNextContainer ty $ do OID f <- getNext v <- getMany getNext return OtherRevocationInfoFormat { otherRevInfoFormat = f , otherRevInfoValues = v } cryptostore-0.3.1.0/src/Crypto/Store/CMS/PEM.hs0000644000000000000000000000457707346545000017216 0ustar0000000000000000-- | -- Module : Crypto.Store.CMS.PEM -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- PEM serialization and deserialization of CMS 'ContentInfo'. module Crypto.Store.CMS.PEM ( readCMSFile , readCMSFileFromMemory , berToContentInfo , pemToContentInfo , writeCMSFile , writeCMSFileToMemory , contentInfoToDER , contentInfoToPEM ) where import qualified Data.ByteString as B import Data.Maybe (catMaybes) import Crypto.Store.CMS.Info import Crypto.Store.CMS.Util import Crypto.Store.Error import Crypto.Store.PEM -- Reading from PEM format -- | Read content info elements from a PEM file. readCMSFile :: FilePath -> IO [ContentInfo] readCMSFile path = accumulate <$> readPEMs path -- | Read content info elements from a bytearray in PEM format. readCMSFileFromMemory :: B.ByteString -> [ContentInfo] readCMSFileFromMemory = either (const []) accumulate . pemParseBS accumulate :: [PEM] -> [ContentInfo] accumulate = catMaybes . foldr (flip pemToContentInfo) [] -- | Read a content info from a bytearray in BER format. berToContentInfo :: B.ByteString -> Either StoreError ContentInfo berToContentInfo = decodeASN1Object -- | Read a content info from a 'PEM' element and add it to the accumulator -- list. pemToContentInfo :: [Maybe ContentInfo] -> PEM -> [Maybe ContentInfo] pemToContentInfo acc pem | pemName pem `elem` names = decode (pemContent pem) | otherwise = Nothing : acc where names = [ "CMS", "PKCS7" ] decode bs = case berToContentInfo bs of Left _ -> Nothing : acc Right info -> Just info : acc -- Writing to PEM format -- | Write content info elements to a PEM file. writeCMSFile :: FilePath -> [ContentInfo] -> IO () writeCMSFile path = B.writeFile path . writeCMSFileToMemory -- | Write content info elements to a bytearray in PEM format. writeCMSFileToMemory :: [ContentInfo] -> B.ByteString writeCMSFileToMemory = pemsWriteBS . map contentInfoToPEM -- | Generate a bytearray in DER format for a content info. contentInfoToDER :: ContentInfo -> B.ByteString contentInfoToDER = encodeASN1Object -- | Generate PEM for a content info. contentInfoToPEM :: ContentInfo -> PEM contentInfoToPEM info = PEM { pemName = "CMS", pemHeader = [], pemContent = bs} where bs = contentInfoToDER info cryptostore-0.3.1.0/src/Crypto/Store/CMS/Signed.hs0000644000000000000000000003206607346545000020000 0ustar0000000000000000-- | -- Module : Crypto.Store.CMS.Signed -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RecordWildCards #-} module Crypto.Store.CMS.Signed ( EncapsulatedContent , SignedData(..) , SignerInfo(..) , SignerIdentifier(..) , IssuerAndSerialNumber(..) , ProducerOfSI , ConsumerOfSI , certSigner , withPublicKey , withSignerKey , withSignerCertificate , encapsulatedContentInfoASN1S , parseEncapsulatedContentInfo ) where import Control.Applicative import Control.Monad import Data.ASN1.Types import Data.ByteString (ByteString) import qualified Data.ByteString as B import Data.Hourglass import Data.List import Data.Maybe import Data.X509 import Crypto.Random (MonadRandom) import Crypto.Store.ASN1.Generate import Crypto.Store.ASN1.Parse import Crypto.Store.CMS.Algorithms import Crypto.Store.CMS.AuthEnveloped import Crypto.Store.CMS.Attribute import Crypto.Store.CMS.Enveloped import Crypto.Store.CMS.OriginatorInfo import Crypto.Store.CMS.Type import Crypto.Store.CMS.Util import Crypto.Store.Error -- | Encapsulated content. type EncapsulatedContent = ByteString -- | Information related to a signer of a 'Crypto.Store.CMS.SignedData'. An -- element contains the signature material that was produced. data SignerInfo = SignerInfo { siSignerId :: SignerIdentifier -- ^ Identifier of the signer certificate , siDigestAlgorithm :: DigestAlgorithm -- ^ Digest algorithm used for the signature , siSignedAttrs :: [Attribute] -- ^ Optional signed attributes , siSignatureAlg :: SignatureAlg -- ^ Algorithm used for signature , siSignature :: SignatureValue -- ^ The signature value , siUnsignedAttrs :: [Attribute] -- ^ Optional unsigned attributes } deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e SignerInfo where asn1s SignerInfo{..} = asn1Container Sequence (ver . sid . dig . sa . alg . sig . ua) where ver = gIntVal (getVersion siSignerId) sid = asn1s siSignerId dig = algorithmASN1S Sequence siDigestAlgorithm sa = attributesASN1S (Container Context 0) siSignedAttrs alg = algorithmASN1S Sequence siSignatureAlg sig = gOctetString siSignature ua = attributesASN1S (Container Context 1) siUnsignedAttrs instance Monoid e => ParseASN1Object e SignerInfo where parse = onNextContainer Sequence $ do IntVal v <- getNext when (v /= 1 && v /= 3) $ throwParseError ("SignerInfo: parsed invalid version: " ++ show v) sid <- parse dig <- parseAlgorithm Sequence sAttrs <- parseAttributes (Container Context 0) alg <- parseAlgorithm Sequence OctetString sig <- getNext uAttrs <- parseAttributes (Container Context 1) return SignerInfo { siSignerId = sid , siDigestAlgorithm = dig , siSignedAttrs = sAttrs , siSignatureAlg = alg , siSignature = sig , siUnsignedAttrs = uAttrs } getVersion :: SignerIdentifier -> Integer getVersion (SignerIASN _) = 1 getVersion (SignerSKI _) = 3 -- | Return true when the signer info has version 3. isVersion3 :: SignerInfo -> Bool isVersion3 = (== 3) . getVersion . siSignerId -- | Union type related to identification of the signer certificate. data SignerIdentifier = SignerIASN IssuerAndSerialNumber -- ^ Issuer and Serial Number | SignerSKI ByteString -- ^ Subject Key Identifier deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e SignerIdentifier where asn1s (SignerIASN iasn) = asn1s iasn asn1s (SignerSKI ski) = asn1Container (Container Context 0) (gOctetString ski) instance Monoid e => ParseASN1Object e SignerIdentifier where parse = parseIASN <|> parseSKI where parseIASN = SignerIASN <$> parse parseSKI = SignerSKI <$> onNextContainer (Container Context 0) parseOctetStringPrim -- | Try to find a certificate with the specified identifier. findSigner :: SignerIdentifier -> [SignedCertificate] -> Maybe (SignedCertificate, [SignedCertificate]) findSigner (SignerIASN iasn) certs = partitionHead (matchIASN . signedObject . getSigned) certs where matchIASN c = (iasnIssuer iasn, iasnSerial iasn) == (certIssuerDN c, certSerial c) findSigner (SignerSKI ski) certs = partitionHead (matchSKI. signedObject . getSigned) certs where matchSKI c = case extensionGet (certExtensions c) of Just (ExtSubjectKeyId idBs) -> idBs == ski Nothing -> False partitionHead :: (a -> Bool) -> [a] -> Maybe (a, [a]) partitionHead p l = case partition p l of (x : _, r) -> Just (x, r) ([] , _) -> Nothing -- | Function able to produce a 'SignerInfo'. type ProducerOfSI m = ContentType -> ByteString -> m (Either StoreError (SignerInfo, [CertificateChoice], [RevocationInfoChoice])) -- | Function able to consume a 'SignerInfo'. type ConsumerOfSI m = ContentType -> ByteString -> SignerInfo -> [CertificateChoice] -> [RevocationInfoChoice] -> m Bool -- | Create a signer info with the specified signature algorithm and -- credentials. -- -- Two lists of optional attributes can be provided. The attributes will be -- part of message signature when provided in the first list. -- -- When the first list of attributes is provided, even empty list, signature is -- computed from a digest of the content. When the list of attributes is -- 'Nothing', no intermediate digest is used and the signature is computed from -- the full message. certSigner :: MonadRandom m => SignatureAlg -> PrivKey -> CertificateChain -> Maybe [Attribute] -> [Attribute] -> ProducerOfSI m certSigner _ _ (CertificateChain []) _ _ _ _ = pure $ Left (InvalidInput "Empty certificate chain") certSigner alg priv (CertificateChain chain@(cert:_)) sAttrsM uAttrs ct msg = fmap build <$> generate where md = digest dig msg def = DigestAlgorithm Crypto.Store.CMS.Algorithms.SHA256 obj = signedObject (getSigned cert) isn = IssuerAndSerialNumber (certIssuerDN obj) (certSerial obj) pub = certPubKey obj (dig, alg') = signatureResolveHash noAttr def alg noAttr = null sAttrs (sAttrs, input) = case sAttrsM of Nothing -> ([], msg) Just attrs -> let l = setContentTypeAttr ct $ setMessageDigestAttr md attrs in (l, encodeAuthAttrs l) generate = signatureGenerate alg' priv pub input build sig = let si = SignerInfo { siSignerId = SignerIASN isn , siDigestAlgorithm = dig , siSignedAttrs = sAttrs , siSignatureAlg = alg , siSignature = sig , siUnsignedAttrs = uAttrs } in (si, map CertificateCertificate chain, []) -- | Verify that the signature was produced from the specified public key. -- Ignores all certificates and CRLs contained in the signed data. withPublicKey :: Applicative f => PubKey -> ConsumerOfSI f withPublicKey pub ct msg SignerInfo{..} _ _ = pure $ fromMaybe False $ do guard (noAttr || attrMatch) guard mdAccept alg <- signatureCheckHash siDigestAlgorithm siSignatureAlg return (signatureVerify alg pub input siSignature) where noAttr = null siSignedAttrs mdMatch = mdAttr == Just (digest siDigestAlgorithm msg) attrMatch = ctAttr == Just ct && mdMatch mdAttr = getMessageDigestAttr siSignedAttrs mdAccept = securityAcceptable siDigestAlgorithm ctAttr = getContentTypeAttr siSignedAttrs input = if noAttr then msg else encodeAuthAttrs siSignedAttrs -- | Verify that the signature is valid with one of the X.509 certificates -- contained in the signed data, but does not validate that the certificates are -- valid. All transmitted certificates are implicitely trusted and all CRLs are -- ignored. withSignerKey :: Applicative f => ConsumerOfSI f withSignerKey = withSignerCertificate (\_ _ -> pure True) -- | Verify that the signature is valid with one of the X.509 certificates -- contained in the signed data, and verify that the signer certificate is valid -- using the validation function supplied. All CRLs are ignored. withSignerCertificate :: Applicative f => (Maybe DateTime -> CertificateChain -> f Bool) -> ConsumerOfSI f withSignerCertificate validate ct msg SignerInfo{..} certs crls = case getCertificateChain of Just chain -> validate mSigningTime chain Nothing -> pure False where getCertificateChain = do (cert, others) <- findSigner siSignerId x509Certificates let pub = certPubKey $ signedObject $ getSigned cert validSignature <- withPublicKey pub ct msg SignerInfo{..} certs crls guard validSignature return $ CertificateChain (cert : others) mSigningTime = getSigningTimeAttr siSignedAttrs x509Certificates = mapMaybe asX509 certs asX509 (CertificateCertificate c) = Just c asX509 _ = Nothing -- | Signed content information. data SignedData content = SignedData { sdDigestAlgorithms :: [DigestAlgorithm] -- ^ Digest algorithms , sdContentType :: ContentType -- ^ Inner content type , sdEncapsulatedContent :: content -- ^ Encapsulated content , sdCertificates :: [CertificateChoice] -- ^ The collection of certificates , sdCRLs :: [RevocationInfoChoice] -- ^ The collection of CRLs , sdSignerInfos :: [SignerInfo] -- ^ Per-signer information } deriving (Show,Eq) instance ProduceASN1Object ASN1P (SignedData (Encap EncapsulatedContent)) where asn1s SignedData{..} = asn1Container Sequence (ver . dig . ci . certs . crls . sis) where ver = gIntVal v dig = asn1Container Set (digestTypesASN1S sdDigestAlgorithms) ci = encapsulatedContentInfoASN1S sdContentType sdEncapsulatedContent certs = gen 0 sdCertificates crls = gen 1 sdCRLs sis = asn1Container Set (asn1s sdSignerInfos) gen tag list | null list = id | otherwise = asn1Container (Container Context tag) (asn1s list) v | hasChoiceOther sdCertificates = 5 | hasChoiceOther sdCRLs = 5 | any isVersion3 sdSignerInfos = 3 | sdContentType == DataType = 1 | otherwise = 3 instance ParseASN1Object [ASN1Event] (SignedData (Encap EncapsulatedContent)) where parse = onNextContainer Sequence $ do IntVal v <- getNext when (v > 5) $ throwParseError ("SignedData: parsed invalid version: " ++ show v) dig <- onNextContainer Set parseDigestTypes (ct, bs) <- parseEncapsulatedContentInfo certs <- parseOptList 0 crls <- parseOptList 1 sis <- onNextContainer Set parse return SignedData { sdDigestAlgorithms = dig , sdContentType = ct , sdEncapsulatedContent = bs , sdCertificates = certs , sdCRLs = crls , sdSignerInfos = sis } where parseOptList tag = fromMaybe [] <$> onNextContainerMaybe (Container Context tag) parse -- | Generate ASN.1 for EncapsulatedContentInfo. encapsulatedContentInfoASN1S :: ASN1Elem e => ContentType -> Encap EncapsulatedContent -> ASN1Stream e encapsulatedContentInfoASN1S ct ec = asn1Container Sequence (oid . cont) where oid = gOID (getObjectID ct) cont = encapsulatedASN1S (Container Context 0) ec encapsulatedASN1S :: ASN1Elem e => ASN1ConstructionType -> Encap B.ByteString -> ASN1Stream e encapsulatedASN1S _ Detached = id encapsulatedASN1S ty (Attached bs) = asn1Container ty (gOctetString bs) -- | Parse EncapsulatedContentInfo from ASN.1. parseEncapsulatedContentInfo :: Monoid e => ParseASN1 e (ContentType, Encap EncapsulatedContent) parseEncapsulatedContentInfo = onNextContainer Sequence $ do OID oid <- getNext withObjectID "content type" oid $ \ct -> wrap ct <$> onNextContainerMaybe (Container Context 0) parseOctetString where wrap ct Nothing = (ct, Detached) wrap ct (Just c) = (ct, Attached c) digestTypesASN1S :: ASN1Elem e => [DigestAlgorithm] -> ASN1Stream e digestTypesASN1S list cont = foldr (algorithmASN1S Sequence) cont list parseDigestTypes :: Monoid e => ParseASN1 e [DigestAlgorithm] parseDigestTypes = getMany (parseAlgorithm Sequence) cryptostore-0.3.1.0/src/Crypto/Store/CMS/Type.hs0000644000000000000000000000573407346545000017512 0ustar0000000000000000-- | -- Module : Crypto.Store.CMS.Type -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- CMS content information type. {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE TypeFamilies #-} module Crypto.Store.CMS.Type ( ContentType(..) , Encap(..) , fromEncap ) where import Data.ASN1.OID import Crypto.Store.CMS.Util -- | CMS content information type. data ContentType = DataType -- ^ Arbitrary octet string | SignedDataType -- ^ Signed content info | EnvelopedDataType -- ^ Enveloped content info | DigestedDataType -- ^ Content info with associated digest | EncryptedDataType -- ^ Encrypted content info | AuthenticatedDataType -- ^ Authenticated content info | AuthEnvelopedDataType -- ^ Authenticated-enveloped content info deriving (Show,Eq) instance Enumerable ContentType where values = [ DataType , SignedDataType , EnvelopedDataType , DigestedDataType , EncryptedDataType , AuthenticatedDataType , AuthEnvelopedDataType ] instance OIDable ContentType where getObjectID DataType = [1,2,840,113549,1,7,1] getObjectID SignedDataType = [1,2,840,113549,1,7,2] getObjectID EnvelopedDataType = [1,2,840,113549,1,7,3] getObjectID DigestedDataType = [1,2,840,113549,1,7,5] getObjectID EncryptedDataType = [1,2,840,113549,1,7,6] getObjectID AuthenticatedDataType = [1,2,840,113549,1,9,16,1,2] getObjectID AuthEnvelopedDataType = [1,2,840,113549,1,9,16,1,23] instance OIDNameable ContentType where fromObjectID oid = unOIDNW <$> fromObjectID oid -- | Denote the state of encapsulated content in a CMS data structure. This -- type is isomorphic to 'Maybe'. data Encap a = Detached -- ^ Content is stored externally to the structure | Attached a -- ^ Content is stored inside the CMS struture deriving (Show,Eq) instance Functor Encap where fmap _ Detached = Detached fmap f (Attached c) = Attached (f c) instance Applicative Encap where pure = Attached Attached f <*> e = fmap f e Detached <*> _ = Detached instance Foldable Encap where foldMap = fromEncap mempty foldr _ d Detached = d foldr f d (Attached c) = f c d foldl _ d Detached = d foldl f d (Attached c) = f d c instance Traversable Encap where traverse _ Detached = pure Detached traverse f (Attached c) = Attached <$> f c -- | Fold over an 'Encap' value. This is similar to function 'maybe'. If the -- content is detached, the first argument is returned. Otherwise the second -- argument is applied to the content. fromEncap :: b -> (a -> b) -> Encap a -> b fromEncap d _ Detached = d fromEncap _ f (Attached c) = f c cryptostore-0.3.1.0/src/Crypto/Store/CMS/Util.hs0000644000000000000000000002212607346545000017500 0ustar0000000000000000-- | -- Module : Crypto.Store.CMS.Util -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- CMS and ASN.1 utilities {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} module Crypto.Store.CMS.Util ( -- * Testing ASN.1 types nullOrNothing , intOrNothing , dateTimeOrNothing -- * Object Identifiers , OIDTable , lookupOID , Enumerable(..) , OIDNameableWrapper(..) , withObjectID -- * Parsing octet strings , parseOctetString , parseOctetStringPrim , parseOctetStrings -- * Parsing and encoding ASN.1 objects , ASN1Event , ASN1ObjectExact(..) , ProduceASN1Object(..) , encodeASN1Object , ParseASN1Object(..) , decodeASN1Object -- * Algorithm Identifiers , AlgorithmId(..) , algorithmASN1S , algorithmMaybeASN1S , parseAlgorithm , parseAlgorithmMaybe -- * Miscellaneous functions , orElse ) where import Control.Applicative import Data.ASN1.BinaryEncoding import Data.ASN1.BinaryEncoding.Raw import Data.ASN1.Encoding import Data.ASN1.OID import Data.ASN1.Types import Data.ByteString (ByteString) import qualified Data.ByteString as B import Data.List (find) import Data.X509 import Time.Types (DateTime) import Crypto.Store.ASN1.Generate import Crypto.Store.ASN1.Parse import Crypto.Store.Error -- | Try to parse a 'Null' ASN.1 value. nullOrNothing :: ASN1 -> Maybe () nullOrNothing Null = Just () nullOrNothing _ = Nothing -- | Try to parse an 'IntVal' ASN.1 value. intOrNothing :: ASN1 -> Maybe Integer intOrNothing (IntVal i) = Just i intOrNothing _ = Nothing -- | Try to parse a 'DateTime' ASN.1 value. dateTimeOrNothing :: ASN1 -> Maybe DateTime dateTimeOrNothing (ASN1Time _ t _) = Just t dateTimeOrNothing _ = Nothing -- | Mapping between values and OIDs. type OIDTable a = [(a, OID)] -- | Find the value associated to an OID. lookupByOID :: OIDTable a -> OID -> Maybe a lookupByOID table oid = fst <$> find ((==) oid . snd) table -- | Find the OID associated to a value. lookupOID :: Eq a => OIDTable a -> a -> Maybe OID lookupOID table a = lookup a table -- | Types with a finite set of values. class Enumerable a where -- | Return all possible values for the given type. values :: [a] -- | Type used to transform a 'Enumerable' instance to an 'OIDNameable' -- instance. newtype OIDNameableWrapper a = OIDNW { unOIDNW :: a } deriving (Show,Eq) instance (Enumerable a, OIDable a) => OIDNameable (OIDNameableWrapper a) where fromObjectID = lookupByOID table where table = [ (OIDNW val, getObjectID val) | val <- values ] -- | Convert the specified OID and apply a parser to the result. withObjectID :: OIDNameable a => String -> OID -> (a -> ParseASN1 e b) -> ParseASN1 e b withObjectID name oid fn = case fromObjectID oid of Just val -> fn val Nothing -> throwParseError ("Unsupported " ++ name ++ ": OID " ++ show oid) -- | Objects that can produce an ASN.1 stream. class ProduceASN1Object e obj where asn1s :: obj -> ASN1Stream e instance ProduceASN1Object e obj => ProduceASN1Object e [obj] where asn1s l r = foldr asn1s r l instance ASN1Elem e => ProduceASN1Object e DistinguishedName where asn1s = asn1Container Sequence . inner where inner (DistinguishedName dn) cont = foldr dnSet cont dn dnSet (oid, cs) = asn1Container Set $ asn1Container Sequence (gOID oid . gASN1String cs) instance (Show a, Eq a, ASN1Object a) => ProduceASN1Object ASN1P (SignedExact a) where asn1s = gEncoded . encodeSignedObject -- | Encode the ASN.1 object to DER format. encodeASN1Object :: ProduceASN1Object ASN1P obj => obj -> ByteString encodeASN1Object = encodeASN1S . asn1s -- | Objects that can be parsed from an ASN.1 stream. class Monoid e => ParseASN1Object e obj where parse :: ParseASN1 e obj instance ParseASN1Object e obj => ParseASN1Object e [obj] where parse = getMany parse instance Monoid e => ParseASN1Object e DistinguishedName where parse = DistinguishedName <$> onNextContainer Sequence inner where inner = concat <$> getMany parseOne parseOne = onNextContainer Set $ getMany $ onNextContainer Sequence $ do OID oid <- getNext ASN1String cs <- getNext return (oid, cs) instance (Show a, Eq a, ASN1Object a) => ParseASN1Object [ASN1Event] (SignedExact a) where parse = withAnnotations parseSequence >>= finish where parseSequence = onNextContainer Sequence (getMany getNext) finish (_, events) = case decodeSignedObject (toByteString events) of Right se -> return se Left err -> throwParseError ("SignedExact: " ++ err) -- | Create an ASN.1 object from a bytearray in BER format. decodeASN1Object :: ParseASN1Object [ASN1Event] obj => ByteString -> Either StoreError obj decodeASN1Object bs = case decodeASN1Repr' BER bs of Left e -> Left (DecodingError e) Right asn1 -> case runParseASN1State_ parse asn1 of Right (obj, []) -> Right obj Right _ -> Left (ParseFailure "Incomplete parse") Left e -> Left (ParseFailure e) -- | An ASN.1 object associated with the raw data it was parsed from. data ASN1ObjectExact a = ASN1ObjectExact { exactObject :: a -- ^ The wrapped ASN.1 object , exactObjectRaw :: ByteString -- ^ The raw representation of this object } deriving Show instance Eq a => Eq (ASN1ObjectExact a) where a == b = exactObject a == exactObject b instance ProduceASN1Object ASN1P a => ProduceASN1Object ASN1P (ASN1ObjectExact a) where asn1s = gEncoded . exactObjectRaw instance ParseASN1Object [ASN1Event] a => ParseASN1Object [ASN1Event] (ASN1ObjectExact a) where parse = do (obj, events) <- withAnnotations parse let objRaw = toByteString events return ASN1ObjectExact { exactObject = obj, exactObjectRaw = objRaw } -- | Algorithm identifier with associated parameter. class AlgorithmId param where type AlgorithmType param algorithmName :: param -> String algorithmType :: param -> AlgorithmType param parameterASN1S :: ASN1Elem e => param -> ASN1Stream e parseParameter :: Monoid e => AlgorithmType param -> ParseASN1 e param -- | Transform the algorithm identifier to ASN.1 stream. algorithmASN1S :: (ASN1Elem e, AlgorithmId param, OIDable (AlgorithmType param)) => ASN1ConstructionType -> param -> ASN1Stream e algorithmASN1S ty p = asn1Container ty (oid . parameterASN1S p) where typ = algorithmType p oid = gOID (getObjectID typ) -- | Transform the optional algorithm identifier to ASN.1 stream. algorithmMaybeASN1S :: (ASN1Elem e, AlgorithmId param, OIDable (AlgorithmType param)) => ASN1ConstructionType -> Maybe param -> ASN1Stream e algorithmMaybeASN1S _ Nothing = id algorithmMaybeASN1S ty (Just p) = algorithmASN1S ty p -- | Parse an algorithm identifier from an ASN.1 stream. parseAlgorithm :: forall e param . (Monoid e, AlgorithmId param, OIDNameable (AlgorithmType param)) => ASN1ConstructionType -> ParseASN1 e param parseAlgorithm ty = onNextContainer ty $ do OID oid <- getNext withObjectID (getName undefined) oid parseParameter where getName :: param -> String getName = algorithmName -- | Parse an optional algorithm identifier from an ASN.1 stream. parseAlgorithmMaybe :: forall e param . (Monoid e, AlgorithmId param, OIDNameable (AlgorithmType param)) => ASN1ConstructionType -> ParseASN1 e (Maybe param) parseAlgorithmMaybe ty = onNextContainerMaybe ty $ do OID oid <- getNext withObjectID (getName undefined) oid parseParameter where getName :: param -> String getName = algorithmName -- | Execute the second action only if the first action produced 'Nothing'. orElse :: Monad m => m (Maybe a) -> m (Maybe a) -> m (Maybe a) orElse pa pb = do va <- pa case va of Nothing -> pb _ -> return va -- | Parse an octet string, in primitive or constructed encodings. parseOctetString :: Monoid e => ParseASN1 e ByteString parseOctetString = parseOctetStringPrim <|> parseConstructed where parseConstructed = onNextContainer (Container Universal 4) parseOctetStrings -- | Parse an octet string in primitive encoding. parseOctetStringPrim :: Monoid e => ParseASN1 e ByteString parseOctetStringPrim = do next <- getNext case next of OctetString bs -> return bs _ -> throwParseError "parseOctetStringPrim: parsed unexpected content" -- | Parse some octet strings, in primitive or constructed encodings, and -- concatenate the result. parseOctetStrings :: Monoid e => ParseASN1 e ByteString parseOctetStrings = B.concat <$> getMany parseOctetString cryptostore-0.3.1.0/src/Crypto/Store/Cipher/0000755000000000000000000000000007346545000017014 5ustar0000000000000000cryptostore-0.3.1.0/src/Crypto/Store/Cipher/RC2.hs0000644000000000000000000000340407346545000017737 0ustar0000000000000000-- | -- Module : Crypto.Store.Cipher.RC2 -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : stable -- Portability : good -- -- Implementation of RC2 block cipher, a legacy algorithm providing weak -- security. Use only for compatibility with software requiring this cipher and -- data which is not sensitive. module Crypto.Store.Cipher.RC2 ( RC2 , rc2WithEffectiveKeyLength ) where import Data.ByteArray (ByteArrayAccess) import qualified Data.ByteArray as B import Data.Maybe (fromMaybe) import Crypto.Error import Crypto.Cipher.Types import Crypto.Store.Cipher.RC2.Primitive import Crypto.Store.Util -- | RC2 block cipher. Key is between 8 and 1024 bits. newtype RC2 = RC2 Key instance Cipher RC2 where cipherName _ = "RC2" cipherKeySize _ = KeySizeRange 1 128 cipherInit = fmap RC2 . initRC2 Nothing instance BlockCipher RC2 where blockSize _ = 8 ecbEncrypt (RC2 k) = mapAsWord64LE (encrypt k) ecbDecrypt (RC2 k) = mapAsWord64LE (decrypt k) -- | Build a RC2 cipher with the specified effective key length (in bits). rc2WithEffectiveKeyLength :: ByteArrayAccess key => Int -> key -> CryptoFailable RC2 rc2WithEffectiveKeyLength bits key | bits < 1 = CryptoFailed CryptoError_KeySizeInvalid | bits > 1024 = CryptoFailed CryptoError_KeySizeInvalid | otherwise = RC2 <$> initRC2 (Just bits) key initRC2 :: ByteArrayAccess key => Maybe Int -> key -> CryptoFailable Key initRC2 mbits bs | len < 1 = CryptoFailed CryptoError_KeySizeInvalid | len <= 128 = CryptoPassed (buildKey t1 bs) | otherwise = CryptoFailed CryptoError_KeySizeInvalid where len = B.length bs t1 = fromMaybe (8 * len) mbits cryptostore-0.3.1.0/src/Crypto/Store/Cipher/RC2/0000755000000000000000000000000007346545000017402 5ustar0000000000000000cryptostore-0.3.1.0/src/Crypto/Store/Cipher/RC2/Primitive.hs0000644000000000000000000001570307346545000021714 0ustar0000000000000000-- | -- Module : Crypto.Store.Cipher.RC2.Primitive -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : stable -- Portability : good -- {-# LANGUAGE Rank2Types #-} module Crypto.Store.Cipher.RC2.Primitive ( Key , buildKey , encrypt , decrypt ) where import Basement.Block import Basement.Compat.IsList import Basement.Endianness import Basement.Types.OffsetSize import Control.Monad (forM_) import Data.Bits import Data.ByteArray (ByteArrayAccess) import qualified Data.ByteArray as B import Data.Word import Foreign.Storable -- | Expanded RC2 key newtype Key = Key (Block Word16) -- [ K[0], K[1], ..., K[63] ] data Q = Q {-# UNPACK #-} !Word16 {-# UNPACK #-} !Word16 {-# UNPACK #-} !Word16 {-# UNPACK #-} !Word16 -- Utilities decomp64 :: Word64 -> Q decomp64 x = let d = fromIntegral (x `shiftR` 48) c = fromIntegral (x `shiftR` 32) b = fromIntegral (x `shiftR` 16) a = fromIntegral x in Q a b c d comp64 :: Q -> Word64 comp64 (Q a b c d) = (fromIntegral d `shiftL` 48) .|. (fromIntegral c `shiftL` 32) .|. (fromIntegral b `shiftL` 16) .|. fromIntegral a getR :: Q -> Word8 -> Word16 getR (Q a b c d) i = case i .&. 3 of 0 -> a 1 -> b 2 -> c _ -> d {-# INLINE getR #-} setR :: Q -> Word8 -> Word16 -> Q setR (Q a b c d) i x = case i .&. 3 of 0 -> Q x b c d 1 -> Q a x c d 2 -> Q a b x d _ -> Q a b c x {-# INLINE setR #-} rol :: Word8 -> Word16 -> Word16 rol i = case i .&. 3 of 0 -> flip rotateL 1 1 -> flip rotateL 2 2 -> flip rotateL 3 _ -> flip rotateL 5 {-# INLINE rol #-} ror :: Word8 -> Word16 -> Word16 ror i = case i .&. 3 of 0 -> flip rotateR 1 1 -> flip rotateR 2 2 -> flip rotateR 3 _ -> flip rotateR 5 {-# INLINE ror #-} f5 :: (a -> a) -> a -> a f5 f = f . f . f . f . f f6 :: (a -> a) -> a -> a f6 f = f . f . f . f . f . f -- Encryption -- | Encrypts a block using the specified key encrypt :: Key -> Word64 -> Word64 encrypt k = comp64 . enc k . decomp64 enc :: Key -> Q -> Q enc k r = fst $ f5 (mixingRound k) $ mashingRound k $ f6 (mixingRound k) $ mashingRound k $ f5 (mixingRound k) (r, 0) -- Decryption -- | Decrypts a block using the specified key decrypt :: Key -> Word64 -> Word64 decrypt k = comp64 . dec k . decomp64 dec :: Key -> Q -> Q dec k r = fst $ f5 (rmixingRound k) $ rmashingRound k $ f6 (rmixingRound k) $ rmashingRound k $ f5 (rmixingRound k) (r, 63) -- Encryptiong rounds mixUp :: Key -> Word8 -> (Q, Int) -> (Q, Int) mixUp k i input@(r, j) = seq r' $ seq j' (r', j') where j' = j + 1 r' = setR r i (rol i (ri + gmix k i input)) ri = getR r i {-# INLINE mixUp #-} mixingRound :: Key -> (Q, Int) -> (Q, Int) mixingRound k = mixUp k 3 . mixUp k 2 . mixUp k 1 . mixUp k 0 mash :: Key -> Word8 -> (Q, Int) -> (Q, Int) mash = gmash (+) {-# INLINE mash #-} mashingRound :: Key -> (Q, Int) -> (Q, Int) mashingRound k = mash k 3 . mash k 2 . mash k 1 . mash k 0 -- Decryption rounds rmixUp :: Key -> Word8 -> (Q, Int) -> (Q, Int) rmixUp k i input@(r, j) = seq r' $ seq j' (r', j') where j' = j - 1 r' = setR r i (ri - gmix k i input) ri = ror i (getR r i) {-# INLINE rmixUp #-} rmixingRound :: Key -> (Q, Int) -> (Q, Int) rmixingRound k = rmixUp k 0 . rmixUp k 1 . rmixUp k 2 . rmixUp k 3 rmash :: Key -> Word8 -> (Q, Int) -> (Q, Int) rmash = gmash (-) {-# INLINE rmash #-} rmashingRound :: Key -> (Q, Int) -> (Q, Int) rmashingRound k = rmash k 0 . rmash k 1 . rmash k 2 . rmash k 3 -- Generic rounds gmix :: Key -> Word8 -> (Q, Int) -> Word16 gmix (Key k) i (r, j) = kj + (ri1 .&. ri2) + (complement ri1 .&. ri3) where ri1 = getR r (i - 1) ri2 = getR r (i - 2) ri3 = getR r (i - 3) kj = unsafeIndex k (Offset j) {-# INLINE gmix #-} gmash :: (Word16 -> Word16 -> Word16) -> Key -> Word8 -> (Q, Int) -> (Q, Int) gmash op (Key k) i (r, j) = seq r' $ seq j (r', j) where r' = setR r i (ri `op` kp) ri = getR r i ri1 = getR r (i - 1) kp = unsafeIndex k $ Offset (fromIntegral ri1 .&. 63) {-# INLINE gmash #-} -- Key expansion -- | Perform key expansion buildKey :: ByteArrayAccess key => Int -- ^ Effective key length in bits -> key -- ^ Input key between 1 and 128 bytes -> Key -- ^ Expanded key buildKey t1 key = Key $ doCast $ B.allocAndFreeze 128 $ \p -> do B.copyByteArrayToPtr key p forM_ [t .. 127] $ \i -> do pos <- (+) <$> peekElemOff p (i - 1) <*> peekElemOff p (i - t) let b = unsafeIndex piTable (fromIntegral pos) pokeElemOff p i b pos' <- (.&. tm) <$> peekElemOff p (128 - t8) let b' = unsafeIndex piTable (fromIntegral pos') pokeElemOff p (128 - t8) b' forM_ (Prelude.reverse [0 .. 127 - t8]) $ \i -> do pos <- xor <$> peekElemOff p (i + 1) <*> peekElemOff p (i + t8) let b = unsafeIndex piTable (fromIntegral pos) pokeElemOff p i b where t = B.length key t8 = (t1 + 7) `div` 8 tm | t1 == 8 * t8 = 255 | otherwise = 255 `mod` shiftL 1 (8 + t1 - 8 * t8) doCast :: Block Word8 -> Block Word16 doCast = Basement.Block.map fromLE . cast -- PITABLE piTable :: Block Word8 piTable = fromList [ 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d , 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2 , 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32 , 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82 , 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc , 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26 , 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03 , 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7 , 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a , 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec , 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39 , 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31 , 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9 , 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9 , 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e , 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad ] cryptostore-0.3.1.0/src/Crypto/Store/Error.hs0000644000000000000000000000457307346545000017240 0ustar0000000000000000-- | -- Module : Crypto.Store.Error -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- Error data type. module Crypto.Store.Error ( StoreError(..) , fromCryptoFailable ) where import Crypto.Error import Crypto.PubKey.RSA.Types as RSA import Data.ASN1.Error -- | Error type in cryptostore. data StoreError = CryptoError CryptoError -- ^ Wraps a cryptonite error | RSAError RSA.Error -- ^ Wraps an RSA crypto error | DecodingError ASN1Error -- ^ Error while decoding ASN.1 content | ParseFailure String -- ^ Error while parsing an ASN.1 object | DecryptionFailed -- ^ Unable to decrypt, incorrect key or password? | BadContentMAC -- ^ MAC verification failed, incorrect key or password? | BadChecksum -- ^ Checksum verification failed, incorrect key or password? | DigestMismatch -- ^ Digest verification failed | SignatureNotVerified -- ^ Signature verification failed | InvalidInput String -- ^ Some condition is not met about input to algorithm | InvalidPassword String -- ^ Some condition is not met about input password | InvalidParameter String -- ^ Some condition is not met about algorithm parameters | UnexpectedPublicKeyType -- ^ The algorithm expects another public key type | UnexpectedPrivateKeyType -- ^ The algorithm expects another private key type | RecipientTypeMismatch -- ^ Returned when the type of recipient info does not match the consumer -- function | RecipientKeyNotFound -- ^ The certificate provided does not match any encrypted key found | NoRecipientInfoFound -- ^ No recipient info is available in the enveloped data | NoRecipientInfoMatched -- ^ No recipient info could be used with the consumer function | UnsupportedOriginatorFormat -- ^ Only anonymous public key is supported | UnsupportedEllipticCurve -- ^ The elliptic curve used is not supported | NamedCurveRequired -- ^ The algorithm requires a named elliptic curve deriving (Show,Eq) -- | Turn a 'CryptoFailed' into a 'StoreError'. fromCryptoFailable ::CryptoFailable a -> Either StoreError a fromCryptoFailable (CryptoPassed a) = Right a fromCryptoFailable (CryptoFailed e) = Left (CryptoError e) cryptostore-0.3.1.0/src/Crypto/Store/KeyWrap/0000755000000000000000000000000007346545000017164 5ustar0000000000000000cryptostore-0.3.1.0/src/Crypto/Store/KeyWrap/AES.hs0000644000000000000000000001243707346545000020137 0ustar0000000000000000-- | -- Module : Crypto.Store.KeyWrap.AES -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- AES Key Wrap () and Extended -- Key Wrap () -- -- Should be used with a cipher from module "Crypto.Cipher.AES". {-# LANGUAGE BangPatterns #-} module Crypto.Store.KeyWrap.AES ( wrap , unwrap , wrapPad , unwrapPad ) where import Data.Bits import Data.ByteArray (ByteArray, ByteArrayAccess, Bytes) import qualified Data.ByteArray as B import Data.List import Data.Word import Crypto.Cipher.Types import Foreign.Storable import Crypto.Store.Error import Crypto.Store.Util type Chunked ba = [ba] type Pair ba = (ba, ba) -- TODO: should use a low-level AES implementation to reduce allocations aes' :: (BlockCipher aes, ByteArray ba) => aes -> Pair ba -> ba aes' cipher (msb, lsb) = ecbEncrypt cipher (B.append msb lsb) aes :: (BlockCipher aes, ByteArray ba) => aes -> Pair ba -> Pair ba aes cipher = B.splitAt 8 . aes' cipher aesrev' :: (BlockCipher aes, ByteArray ba) => aes -> ba -> Pair ba aesrev' cipher = B.splitAt 8 . ecbDecrypt cipher aesrev :: (BlockCipher aes, ByteArray ba) => aes -> Pair ba -> Pair ba aesrev cipher (msb, lsb) = aesrev' cipher (B.append msb lsb) wrapc :: (BlockCipher aes, ByteArray ba) => aes -> ba -> Chunked ba -> Chunked ba wrapc cipher iiv list = uncurry (:) $ foldl' pass (iiv, list) [0 .. 5] where !n = fromIntegral (length list) pass (a, l) j = go a (n * j + 1) l go a !_ [] = (a, []) go a !i (r : rs) = let (a', t) = aes cipher (a, r) in (t :) <$> go (xorWith a' i) (succ i) rs unwrapc :: (BlockCipher aes, ByteArray ba) => aes -> Chunked ba -> Either StoreError (ba, Chunked ba) unwrapc _ [] = Left (InvalidInput "KeyWrap.AES: input too short") unwrapc cipher (iv:list) = Right (iiv, reverse out) where (iiv, out) = foldl' pass (iv, reverse list) (reverse [0 .. 5]) !n = fromIntegral (length list) pass (a, l) j = go a (n * j + n) l go a !_ [] = (a, []) go a !i (r : rs) = let (a', t) = aesrev cipher (xorWith a i, r) in (t :) <$> go a' (pred i) rs -- | Wrap a key with the specified AES cipher. wrap :: (BlockCipher aes, ByteArray ba) => aes -> ba -> Either StoreError ba wrap cipher bs = unchunks . wrapc cipher iiv <$> chunks bs where iiv = B.replicate 8 0xA6 -- | Unwrap an encrypted key with the specified AES cipher. unwrap :: (BlockCipher aes, ByteArray ba) => aes -> ba -> Either StoreError ba unwrap cipher bs = unchunks <$> (check =<< unwrapc cipher =<< chunks bs) where check (iiv, out) | constAllEq 0xA6 iiv = Right out | otherwise = Left BadChecksum chunks :: ByteArray ba => ba -> Either StoreError (Chunked ba) chunks bs | B.null bs = Right [] | B.length bs < 8 = Left (InvalidInput "KeyWrap.AES: input is not multiple of 8 bytes") | otherwise = let (a, b) = B.splitAt 8 bs in (a :) <$> chunks b unchunks :: ByteArray ba => Chunked ba -> ba unchunks = B.concat padMask :: Bytes padMask = B.pack [0xA6, 0x59, 0x59, 0xA6, 0x00, 0x00, 0x00, 0x00] pad :: ByteArray ba => Int -> ba -> Either StoreError (Pair ba) pad inlen bs | inlen == 0 = Left (InvalidInput "KeyWrap.AES: input is empty") | padlen == 8 = Right (aiv, bs) | otherwise = Right (aiv, bs `B.append` B.zero padlen) where padlen = 8 - mod inlen 8 aiv = xorWith padMask (fromIntegral inlen) unpad :: ByteArray ba => Int -> Pair ba -> Either StoreError ba unpad inlen (aiv, b) | badlen = Left BadChecksum | constAllEq 0 p = Right bs | otherwise = Left BadChecksum where aivlen = fromIntegral (unxor padMask aiv) badlen = inlen < aivlen + 8 || inlen >= aivlen + 16 (bs, p) = B.splitAt aivlen b -- | Pad and wrap a key with the specified AES cipher. wrapPad :: (BlockCipher aes, ByteArray ba) => aes -> ba -> Either StoreError ba wrapPad cipher bs = doWrap =<< pad inlen bs where inlen = B.length bs doWrap (aiv, b) | inlen <= 8 = Right $ aes' cipher (aiv, b) | otherwise = unchunks . wrapc cipher aiv <$> chunks b -- | Unwrap and unpad an encrypted key with the specified AES cipher. unwrapPad :: (BlockCipher aes, ByteArray ba) => aes -> ba -> Either StoreError ba unwrapPad cipher bs = unpad inlen =<< doUnwrap where inlen = B.length bs doUnwrap | inlen == 16 = let (aiv, b) = aesrev' cipher bs in Right (aiv, b) | otherwise = fmap unchunks <$> (unwrapc cipher =<< chunks bs) xorWith :: (ByteArrayAccess bin, ByteArray bout) => bin -> Word64 -> bout xorWith bs !i = B.copyAndFreeze bs $ \dst -> loop dst len i where !len = B.length bs loop _ 0 !_ = return () loop _ _ 0 = return () -- return early (constant-time not needed) loop p n j = do b <- peekByteOff p (n - 1) let mask = fromIntegral j :: Word8 pokeByteOff p (n - 1) (xor b mask) loop p (n - 1) (shiftR j 8) unxor :: (ByteArrayAccess bx, ByteArrayAccess by) => bx -> by -> Word64 unxor x y = foldl' f 0 $ zipWith xor (B.unpack x) (B.unpack y) where f acc z = shiftL acc 8 + fromIntegral z cryptostore-0.3.1.0/src/Crypto/Store/KeyWrap/RC2.hs0000644000000000000000000000627707346545000020122 0ustar0000000000000000-- | -- Module : Crypto.Store.KeyWrap.RC2 -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- RC2 Key Wrap () -- -- Should be used with a cipher from module "Crypto.Store.Cipher.RC2". module Crypto.Store.KeyWrap.RC2 ( wrap , wrap' , unwrap ) where import Data.ByteArray (ByteArray) import qualified Data.ByteArray as B import Crypto.Cipher.Types import Crypto.Hash import Crypto.Random import Crypto.Store.Error import Crypto.Store.Util checksum :: ByteArray ba => ba -> ba checksum bs = B.convert $ B.takeView (hashWith SHA1 bs) 8 iv4adda22c79e82105 :: B.Bytes iv4adda22c79e82105 = B.pack [0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05] -- | Wrap an RC2 key with the specified RC2 cipher. -- -- Input must be between 0 and 255 bytes. A fresh IV should be generated -- randomly for each invocation. wrap :: (MonadRandom m, BlockCipher cipher, ByteArray ba) => cipher -> IV cipher -> ba -> m (Either StoreError ba) wrap = wrap' (return . Left) randomPad where randomPad f = fmap (Right . f) . getRandomBytes -- | Wrap an RC2 key with the specified RC2 cipher, using the given source of -- random padding data. -- -- Input must be between 0 and 255 bytes. A fresh IV should be generated -- randomly for each invocation. wrap' :: (ByteArray ba, BlockCipher cipher) => (StoreError -> result) -> ((ba -> ba) -> Int -> result) -> cipher -> IV cipher -> ba -> result wrap' failure withRandomPad cipher iv cek | inLen < 256 = withRandomPad f padlen | otherwise = failure (InvalidInput "KeyWrap.RC2: invalid length for content encryption key") where inLen = B.length cek padlen = (7 - inLen) `mod` 8 f pad = let lcek = B.cons (fromIntegral inLen) cek lcekpad = B.append lcek pad lcekpadicv = B.append lcekpad (checksum lcekpad) temp1 = cbcEncrypt cipher iv lcekpadicv temp2 = B.append (B.convert iv) temp1 temp3 = reverseBytes temp2 Just iv' = makeIV iv4adda22c79e82105 in cbcEncrypt cipher iv' temp3 -- | Unwrap an encrypted RC2 key with the specified RC2 cipher. unwrap :: (BlockCipher cipher, ByteArray ba) => cipher -> ba -> Either StoreError ba unwrap cipher wrapped | inLen <= 16 = invalid | inLen `mod` 8 /= 0 = invalid | checksumPadValid = Right cek | otherwise = invalid where inLen = B.length wrapped Just iv' = makeIV iv4adda22c79e82105 temp3 = cbcDecrypt cipher iv' wrapped temp2 = reverseBytes temp3 (ivBs, temp1) = B.splitAt 8 temp2 Just iv = makeIV ivBs lcekpadicv = cbcDecrypt cipher iv temp1 (lcekpad, icv) = B.splitAt (inLen - 16) lcekpadicv Just (l, cekpad) = B.uncons lcekpad len = fromIntegral l padlen = inLen - 16 - len - 1 cek = B.take len cekpad invalid = Left BadChecksum checksumPadValid = B.constEq icv (checksum lcekpad) &&! padlen >=0 &&! padlen < 8 cryptostore-0.3.1.0/src/Crypto/Store/KeyWrap/TripleDES.hs0000644000000000000000000000425207346545000021316 0ustar0000000000000000-- | -- Module : Crypto.Store.KeyWrap.TripleDES -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- Triple-DES Key Wrap () -- -- Should be used with a cipher from module "Crypto.Cipher.TripleDES". module Crypto.Store.KeyWrap.TripleDES ( wrap , unwrap ) where import Data.ByteArray (ByteArray) import qualified Data.ByteArray as B import Crypto.Cipher.Types import Crypto.Hash import Crypto.Store.Error import Crypto.Store.Util checksum :: ByteArray ba => ba -> ba checksum bs = B.convert $ B.takeView (hashWith SHA1 bs) 8 iv4adda22c79e82105 :: B.Bytes iv4adda22c79e82105 = B.pack [0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05] -- | Wrap a Triple-DES key with the specified Triple-DES cipher. -- -- Input must be 24 bytes. A fresh IV should be generated randomly for each -- invocation. wrap :: (BlockCipher cipher, ByteArray ba) => cipher -> IV cipher -> ba -> Either StoreError ba wrap cipher iv cek | inLen == 24 = Right wrapped | otherwise = Left (InvalidInput "KeyWrap.TripleDES: invalid length for content encryption key") where inLen = B.length cek Just iv' = makeIV iv4adda22c79e82105 cekicv = B.append cek (checksum cek) temp1 = cbcEncrypt cipher iv cekicv temp2 = B.append (B.convert iv) temp1 temp3 = reverseBytes temp2 wrapped = cbcEncrypt cipher iv' temp3 -- | Unwrap an encrypted Triple-DES key with the specified Triple-DES cipher. unwrap :: (BlockCipher cipher, ByteArray ba) => cipher -> ba -> Either StoreError ba unwrap cipher wrapped | inLen /= 40 = invalid | B.constEq icv (checksum cek) = Right cek | otherwise = invalid where inLen = B.length wrapped Just iv' = makeIV iv4adda22c79e82105 temp3 = cbcDecrypt cipher iv' wrapped temp2 = reverseBytes temp3 (ivBs, temp1) = B.splitAt 8 temp2 Just iv = makeIV ivBs cekicv = cbcDecrypt cipher iv temp1 (cek, icv) = B.splitAt 24 cekicv invalid = Left BadChecksum cryptostore-0.3.1.0/src/Crypto/Store/PEM.hs0000644000000000000000000000172007346545000016557 0ustar0000000000000000-- | -- Module : Crypto.Store.PEM -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- Extend module "Data.PEM". module Crypto.Store.PEM ( readPEMs , writePEMs , pemsWriteBS , pemsWriteLBS , module Data.PEM ) where import Data.PEM import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L -- | Read a PEM file from disk. readPEMs :: FilePath -> IO [PEM] readPEMs filepath = either error id . pemParseLBS <$> L.readFile filepath -- | Convert a list of PEM elements to a bytestring. pemsWriteBS :: [PEM] -> B.ByteString pemsWriteBS = L.toStrict . pemsWriteLBS -- | Convert a list of PEM elements to a lazy bytestring. pemsWriteLBS :: [PEM] -> L.ByteString pemsWriteLBS = L.concat . map pemWriteLBS -- | Write a PEM file to disk. writePEMs :: FilePath -> [PEM] -> IO () writePEMs filepath = L.writeFile filepath . pemsWriteLBS cryptostore-0.3.1.0/src/Crypto/Store/PKCS12.hs0000644000000000000000000007454007346545000017053 0ustar0000000000000000-- | -- Module : Crypto.Store.PKCS12 -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- Personal Information Exchange Syntax, aka PKCS #12. -- -- Only password integrity mode and password privacy modes are supported. {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} module Crypto.Store.PKCS12 ( IntegrityParams , readP12File , readP12FileFromMemory , writeP12File , writeP12FileToMemory , writeUnprotectedP12File , writeUnprotectedP12FileToMemory -- * PKCS #12 privacy , PKCS12 , unPKCS12 , unPKCS12' , unencrypted , encrypted -- * PKCS #12 contents and bags , SafeContents(..) , SafeBag , Bag(..) , SafeInfo(..) , CertInfo(..) , CRLInfo(..) , Attribute(..) , getSafeKeys , getAllSafeKeys , getSafeX509Certs , getAllSafeX509Certs , getSafeX509CRLs , getAllSafeX509CRLs -- * PKCS #12 attributes , findAttribute , setAttribute , filterAttributes , getFriendlyName , setFriendlyName , getLocalKeyId , setLocalKeyId -- * Credentials , fromCredential , fromNamedCredential , toCredential , toNamedCredential -- * Password-based protection , Password , OptAuthenticated(..) , recoverAuthenticated , ProtectionPassword , emptyNotTerminated , fromProtectionPassword , toProtectionPassword , OptProtected(..) , recover , recoverA ) where import Control.Monad import Data.ASN1.Types import qualified Data.ByteArray as B import qualified Data.ByteString as BS import Data.List (partition) import Data.Maybe (fromMaybe, mapMaybe) import Data.Semigroup import qualified Data.X509 as X509 import qualified Data.X509.Validation as X509 import Crypto.Cipher.Types import Crypto.Store.ASN1.Generate import Crypto.Store.ASN1.Parse import Crypto.Store.CMS import Crypto.Store.CMS.Algorithms import Crypto.Store.CMS.Attribute import Crypto.Store.CMS.Encrypted import Crypto.Store.CMS.Enveloped import Crypto.Store.CMS.Util import Crypto.Store.Error import Crypto.Store.PKCS5 import Crypto.Store.PKCS5.PBES1 import Crypto.Store.PKCS8 -- Password-based integrity -- | Data type for objects that are possibly authenticated with a password. -- -- Content is verified and retrieved by providing a 'Password' value. When -- verification is successful, a value of type 'ProtectionPassword' is also -- returned and this value can be fed to an inner decryption layer that needs -- the same password (usual case for PKCS #12). data OptAuthenticated a = Unauthenticated a -- ^ Value is not authenticated | Authenticated (Password -> Either StoreError (ProtectionPassword, a)) -- ^ Value is authenticated with a password instance Functor OptAuthenticated where fmap f (Unauthenticated x) = Unauthenticated (f x) fmap f (Authenticated g) = Authenticated (fmap (fmap f) . g) -- | Try to recover an 'OptAuthenticated' content using the specified password. -- -- When successful, the content is returned, as well as the password converted -- to type 'ProtectionPassword'. This password value can then be fed to the -- inner decryption layer when both passwords are known to be same (usual case -- for PKCS #12). recoverAuthenticated :: Password -> OptAuthenticated a -> Either StoreError (ProtectionPassword, a) recoverAuthenticated pwd (Unauthenticated x) = Right (toProtectionPassword pwd, x) recoverAuthenticated pwd (Authenticated f) = f pwd -- Decoding and parsing -- | Read a PKCS #12 file from disk. readP12File :: FilePath -> IO (Either StoreError (OptAuthenticated PKCS12)) readP12File path = readP12FileFromMemory <$> BS.readFile path -- | Read a PKCS #12 file from a bytearray in BER format. readP12FileFromMemory :: BS.ByteString -> Either StoreError (OptAuthenticated PKCS12) readP12FileFromMemory ber = decode ber >>= integrity where integrity PFX{..} = case macData of Nothing -> Unauthenticated <$> decode authSafeData Just md -> return $ Authenticated (verify md authSafeData) verify MacData{..} content pwdUTF8 = case digAlg of DigestAlgorithm d -> loop (toProtectionPasswords pwdUTF8) where -- iterate over all possible representations of a password -- until a successful match is found loop [] = Left BadContentMAC loop (pwd:others) = let fn key macAlg bs | not (securityAcceptable macAlg) = Left (InvalidParameter "Integrity MAC too weak") | macValue == mac macAlg key bs = (pwd,) <$> decode bs | otherwise = loop others in pkcs12mac Left fn d macParams content pwd -- Generating and encoding -- | Parameters used for password integrity mode. type IntegrityParams = (DigestAlgorithm, PBEParameter) -- | Write a PKCS #12 file to disk. writeP12File :: FilePath -> IntegrityParams -> ProtectionPassword -> PKCS12 -> IO (Either StoreError ()) writeP12File path intp pw aSafe = case writeP12FileToMemory intp pw aSafe of Left e -> return (Left e) Right bs -> Right <$> BS.writeFile path bs -- | Write a PKCS #12 file to a bytearray in DER format. writeP12FileToMemory :: IntegrityParams -> ProtectionPassword -> PKCS12 -> Either StoreError BS.ByteString writeP12FileToMemory (alg@(DigestAlgorithm hashAlg), pbeParam) pwdUTF8 aSafe = encode <$> protect where content = encodeASN1Object aSafe encode md = encodeASN1Object PFX { authSafeData = content, macData = Just md } protect = pkcs12mac Left fn hashAlg pbeParam content pwdUTF8 fn key macAlg bs = Right MacData { digAlg = alg , macValue = mac macAlg key bs , macParams = pbeParam } -- | Write a PKCS #12 file without integrity protection to disk. writeUnprotectedP12File :: FilePath -> PKCS12 -> IO () writeUnprotectedP12File path = BS.writeFile path . writeUnprotectedP12FileToMemory -- | Write a PKCS #12 file without integrity protection to a bytearray in DER -- format. writeUnprotectedP12FileToMemory :: PKCS12 -> BS.ByteString writeUnprotectedP12FileToMemory aSafe = encodeASN1Object pfx where content = encodeASN1Object aSafe pfx = PFX { authSafeData = content, macData = Nothing } -- PFX and MacData data PFX = PFX { authSafeData :: BS.ByteString , macData :: Maybe MacData } deriving (Show,Eq) instance ProduceASN1Object ASN1P PFX where asn1s PFX{..} = asn1Container Sequence (v . a . m) where v = gIntVal 3 a = asn1s (DataCI authSafeData) m = optASN1S macData asn1s instance ParseASN1Object [ASN1Event] PFX where parse = onNextContainer Sequence $ do IntVal v <- getNext when (v /= 3) $ throwParseError ("PFX: parsed invalid version: " ++ show v) ci <- parse d <- case ci of DataCI bs -> return bs SignedDataCI _ -> throwParseError "PFX: public-key integrity mode is not supported" _ -> throwParseError $ "PFX: invalid content type: " ++ show (getContentType ci) b <- hasNext m <- if b then Just <$> parse else pure Nothing return PFX { authSafeData = d, macData = m } data MacData = MacData { digAlg :: DigestAlgorithm , macValue :: MessageAuthenticationCode , macParams :: PBEParameter } deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e MacData where asn1s MacData{..} = asn1Container Sequence (m . s . i) where m = asn1Container Sequence (a . v) a = algorithmASN1S Sequence digAlg v = gOctetString (B.convert macValue) s = gOctetString (pbeSalt macParams) i = gIntVal (fromIntegral $ pbeIterationCount macParams) instance Monoid e => ParseASN1Object e MacData where parse = onNextContainer Sequence $ do (a, v) <- onNextContainer Sequence $ do a <- parseAlgorithm Sequence OctetString v <- getNext return (a, v) OctetString s <- getNext b <- hasNext IntVal i <- if b then getNext else pure (IntVal 1) return MacData { digAlg = a , macValue = AuthTag (B.convert v) , macParams = PBEParameter s (fromIntegral i) } -- AuthenticatedSafe -- | PKCS #12 privacy wrapper, adding optional encryption to 'SafeContents'. -- ASN.1 equivalent is @AuthenticatedSafe@. -- -- The semigroup interface allows to combine multiple pieces encrypted -- separately but they should all derive from the same password to be readable -- by 'unPKCS12' and most other software. newtype PKCS12 = PKCS12 [ASElement] deriving (Show,Eq) instance Semigroup PKCS12 where PKCS12 a <> PKCS12 b = PKCS12 (a ++ b) instance ProduceASN1Object ASN1P PKCS12 where asn1s (PKCS12 elems) = asn1Container Sequence (asn1s elems) instance ParseASN1Object [ASN1Event] PKCS12 where parse = PKCS12 <$> onNextContainer Sequence parse -- | Read the contents of a PKCS #12. The same privacy password will be used -- for all content elements. -- -- This convenience function returns a 'Protected' value as soon as one element -- at least is encrypted. This does not mean all elements were actually -- protected in the input. If detailed view is required then function -- 'unPKCS12'' is also available. unPKCS12 :: PKCS12 -> OptProtected [SafeContents] unPKCS12 = applySamePassword . unPKCS12' -- | Read the contents of a PKCS #12. unPKCS12' :: PKCS12 -> [OptProtected SafeContents] unPKCS12' (PKCS12 elems) = map f elems where f (Unencrypted sc) = Unprotected sc f (Encrypted e) = Protected (decrypt e >=> decode) -- | Build a PKCS #12 without encryption. Usage scenario is when private keys -- are already encrypted with 'PKCS8ShroudedKeyBag'. unencrypted :: SafeContents -> PKCS12 unencrypted = PKCS12 . (:[]) . Unencrypted -- | Build a PKCS #12 encrypted with the specified scheme and password. encrypted :: EncryptionScheme -> ProtectionPassword -> SafeContents -> Either StoreError PKCS12 encrypted alg pwd sc = PKCS12 . (:[]) . Encrypted <$> encrypt alg pwd bs where bs = encodeASN1Object sc data ASElement = Unencrypted SafeContents | Encrypted PKCS5 deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e ASElement where asn1s (Unencrypted sc) = asn1Container Sequence (oid . cont) where oid = gOID (getObjectID DataType) cont = asn1Container (Container Context 0) (gOctetString bs) bs = encodeASN1Object sc asn1s (Encrypted PKCS5{..}) = asn1Container Sequence (oid . cont) where oid = gOID (getObjectID EncryptedDataType) cont = asn1Container (Container Context 0) inner inner = asn1Container Sequence (gIntVal 0 . eci) eci = encryptedContentInfoASN1S (DataType, encryptionAlgorithm, Attached encryptedData) instance Monoid e => ParseASN1Object e ASElement where parse = onNextContainer Sequence $ do OID oid <- getNext withObjectID "content type" oid $ \ct -> onNextContainer (Container Context 0) (parseInner ct) where parseInner DataType = Unencrypted <$> parseUnencrypted parseInner EncryptedDataType = Encrypted <$> parseEncrypted parseInner EnvelopedDataType = throwParseError "PKCS12: public-key privacy mode is not supported" parseInner ct = throwParseError $ "PKCS12: invalid content type: " ++ show ct parseUnencrypted = parseOctetStringObject "PKCS12" parseEncrypted = onNextContainer Sequence $ do IntVal 0 <- getNext (DataType, eScheme, Attached ed) <- parseEncryptedContentInfo return PKCS5 { encryptionAlgorithm = eScheme, encryptedData = ed } -- Bags -- | Polymorphic PKCS #12 bag parameterized by the payload data type. data Bag info = Bag { bagInfo :: info -- ^ bag payload , bagAttributes :: [Attribute] -- ^ attributes providing additional information } deriving (Show,Eq) class BagInfo info where type BagType info bagName :: info -> String bagType :: info -> BagType info valueASN1S :: ASN1Elem e => info -> ASN1Stream e parseValue :: Monoid e => BagType info -> ParseASN1 e info instance (ASN1Elem e, BagInfo info, OIDable (BagType info)) => ProduceASN1Object e (Bag info) where asn1s Bag{..} = asn1Container Sequence (oid . val . att) where typ = bagType bagInfo oid = gOID (getObjectID typ) val = asn1Container (Container Context 0) (valueASN1S bagInfo) att | null bagAttributes = id | otherwise = asn1Container Set (asn1s bagAttributes) instance (Monoid e, BagInfo info, OIDNameable (BagType info)) => ParseASN1Object e (Bag info) where parse = onNextContainer Sequence $ do OID oid <- getNext val <- withObjectID (getName undefined) oid $ onNextContainer (Container Context 0) . parseValue att <- fromMaybe [] <$> onNextContainerMaybe Set parse return Bag { bagInfo = val, bagAttributes = att } where getName :: info -> String getName = bagName data CertType = TypeCertX509 deriving (Show,Eq) instance Enumerable CertType where values = [ TypeCertX509 ] instance OIDable CertType where getObjectID TypeCertX509 = [1,2,840,113549,1,9,22,1] instance OIDNameable CertType where fromObjectID oid = unOIDNW <$> fromObjectID oid -- | Certificate bags. Only X.509 certificates are supported. newtype CertInfo = CertX509 X509.SignedCertificate deriving (Show,Eq) instance BagInfo CertInfo where type BagType CertInfo = CertType bagName _ = "CertBag" bagType (CertX509 _) = TypeCertX509 valueASN1S (CertX509 c) = gOctetString (encodeASN1Object c) parseValue TypeCertX509 = CertX509 <$> parseOctetStringObject "CertBag" data CRLType = TypeCRLX509 deriving (Show,Eq) instance Enumerable CRLType where values = [ TypeCRLX509 ] instance OIDable CRLType where getObjectID TypeCRLX509 = [1,2,840,113549,1,9,23,1] instance OIDNameable CRLType where fromObjectID oid = unOIDNW <$> fromObjectID oid -- | CRL bags. Only X.509 CRLs are supported. newtype CRLInfo = CRLX509 X509.SignedCRL deriving (Show,Eq) instance BagInfo CRLInfo where type BagType CRLInfo = CRLType bagName _ = "CRLBag" bagType (CRLX509 _) = TypeCRLX509 valueASN1S (CRLX509 c) = gOctetString (encodeASN1Object c) parseValue TypeCRLX509 = CRLX509 <$> parseOctetStringObject "CRLBag" data SafeType = TypeKey | TypePKCS8ShroudedKey | TypeCert | TypeCRL | TypeSecret | TypeSafeContents deriving (Show,Eq) instance Enumerable SafeType where values = [ TypeKey , TypePKCS8ShroudedKey , TypeCert , TypeCRL , TypeSecret , TypeSafeContents ] instance OIDable SafeType where getObjectID TypeKey = [1,2,840,113549,1,12,10,1,1] getObjectID TypePKCS8ShroudedKey = [1,2,840,113549,1,12,10,1,2] getObjectID TypeCert = [1,2,840,113549,1,12,10,1,3] getObjectID TypeCRL = [1,2,840,113549,1,12,10,1,4] getObjectID TypeSecret = [1,2,840,113549,1,12,10,1,5] getObjectID TypeSafeContents = [1,2,840,113549,1,12,10,1,6] instance OIDNameable SafeType where fromObjectID oid = unOIDNW <$> fromObjectID oid -- | Main bag payload in PKCS #12 contents. data SafeInfo = KeyBag (FormattedKey X509.PrivKey) -- ^ unencrypted private key | PKCS8ShroudedKeyBag PKCS5 -- ^ encrypted private key | CertBag (Bag CertInfo) -- ^ certificate | CRLBag (Bag CRLInfo) -- ^ CRL | SecretBag [ASN1] -- ^ arbitrary secret | SafeContentsBag SafeContents -- ^ safe contents embeded recursively deriving (Show,Eq) instance BagInfo SafeInfo where type BagType SafeInfo = SafeType bagName _ = "SafeBag" bagType (KeyBag _) = TypeKey bagType (PKCS8ShroudedKeyBag _) = TypePKCS8ShroudedKey bagType (CertBag _) = TypeCert bagType (CRLBag _) = TypeCRL bagType (SecretBag _) = TypeSecret bagType (SafeContentsBag _) = TypeSafeContents valueASN1S (KeyBag k) = asn1s k valueASN1S (PKCS8ShroudedKeyBag k) = asn1s k valueASN1S (CertBag c) = asn1s c valueASN1S (CRLBag c) = asn1s c valueASN1S (SecretBag s) = gMany s valueASN1S (SafeContentsBag sc) = asn1s sc parseValue TypeKey = KeyBag <$> parse parseValue TypePKCS8ShroudedKey = PKCS8ShroudedKeyBag <$> parse parseValue TypeCert = CertBag <$> parse parseValue TypeCRL = CRLBag <$> parse parseValue TypeSecret = SecretBag <$> getMany getNext parseValue TypeSafeContents = SafeContentsBag <$> parse -- | Main bag type in a PKCS #12. type SafeBag = Bag SafeInfo -- | Content objects stored in a PKCS #12. newtype SafeContents = SafeContents { unSafeContents :: [SafeBag] } deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e SafeContents where asn1s (SafeContents s) = asn1Container Sequence (asn1s s) instance Monoid e => ParseASN1Object e SafeContents where parse = SafeContents <$> onNextContainer Sequence parse filterBags :: ([Attribute] -> Bool) -> SafeContents -> SafeContents filterBags p (SafeContents scs) = SafeContents (mapMaybe f scs) where f (Bag (SafeContentsBag inner) attrs) = Just (Bag (SafeContentsBag $ filterBags p inner) attrs) f bag | p (bagAttributes bag) = Just bag | otherwise = Nothing filterByFriendlyName :: String -> SafeContents -> SafeContents filterByFriendlyName name = filterBags ((== Just name) . getFriendlyName) filterByLocalKeyId :: BS.ByteString -> SafeContents -> SafeContents filterByLocalKeyId d = filterBags ((== Just d) . getLocalKeyId) getSafeKeysId :: SafeContents -> [OptProtected (Id X509.PrivKey)] getSafeKeysId (SafeContents scs) = loop scs where loop [] = [] loop (bag : bags) = case bagInfo bag of KeyBag (FormattedKey _ k) -> Unprotected (mkId k bag) : loop bags PKCS8ShroudedKeyBag k -> Protected (unshroud k bag) : loop bags SafeContentsBag inner -> getSafeKeysId inner ++ loop bags _ -> loop bags unshroud shrouded bag pwd = do bs <- decrypt shrouded pwd FormattedKey _ k <- decode bs return (mkId k bag) -- | Return all private keys contained in the safe contents. getSafeKeys :: SafeContents -> [OptProtected X509.PrivKey] getSafeKeys = map (fmap unId) . getSafeKeysId getAllSafeKeysId :: [SafeContents] -> OptProtected [Id X509.PrivKey] getAllSafeKeysId = applySamePassword . concatMap getSafeKeysId -- | Return all private keys contained in the safe content list. All shrouded -- private keys must derive from the same password. -- -- This convenience function returns a 'Protected' value as soon as one key at -- least is encrypted. This does not mean all keys were actually protected in -- the input. If detailed view is required then function 'getSafeKeys' is -- available. getAllSafeKeys :: [SafeContents] -> OptProtected [X509.PrivKey] getAllSafeKeys = applySamePassword . concatMap getSafeKeys getSafeX509CertsId :: SafeContents -> [Id X509.SignedCertificate] getSafeX509CertsId (SafeContents scs) = loop scs where loop [] = [] loop (bag : bags) = case bagInfo bag of CertBag (Bag (CertX509 c) _) -> mkId c bag : loop bags SafeContentsBag inner -> getSafeX509CertsId inner ++ loop bags _ -> loop bags -- | Return all X.509 certificates contained in the safe contents. getSafeX509Certs :: SafeContents -> [X509.SignedCertificate] getSafeX509Certs = map unId . getSafeX509CertsId -- | Return all X.509 certificates contained in the safe content list. getAllSafeX509Certs :: [SafeContents] -> [X509.SignedCertificate] getAllSafeX509Certs = concatMap getSafeX509Certs getSafeX509CRLsId :: SafeContents -> [Id X509.SignedCRL] getSafeX509CRLsId (SafeContents scs) = loop scs where loop [] = [] loop (bag : bags) = case bagInfo bag of CRLBag (Bag (CRLX509 c) _) -> mkId c bag : loop bags SafeContentsBag inner -> getSafeX509CRLsId inner ++ loop bags _ -> loop bags -- | Return all X.509 CRLs contained in the safe contents. getSafeX509CRLs :: SafeContents -> [X509.SignedCRL] getSafeX509CRLs = map unId . getSafeX509CRLsId -- | Return all X.509 CRLs contained in the safe content list. getAllSafeX509CRLs :: [SafeContents] -> [X509.SignedCRL] getAllSafeX509CRLs = concatMap getSafeX509CRLs -- Conversion to/from credentials getInnerCredential :: [SafeContents] -> SamePassword (Maybe (X509.CertificateChain, X509.PrivKey)) getInnerCredential l = SamePassword (fn <$> getAllSafeKeysId l) where certs = getAllSafeX509Certs l fn idKeys = do iKey <- single idKeys let k = unId iKey case idKeyId iKey of Just d -> do -- locate a single certificate with same ID as private key -- and follow the issuers to get all certificates in the chain let filtered = map (filterByLocalKeyId d) l leaf <- single (getAllSafeX509Certs filtered) pure (buildCertificateChain leaf certs, k) Nothing -> case idName iKey of Just name -> do -- same but using friendly name of private key let filtered = map (filterByFriendlyName name) l leaf <- single (getAllSafeX509Certs filtered) pure (buildCertificateChain leaf certs, k) Nothing -> do -- no identifier available, so we simply return all -- certificates with input order guard (not $ null certs) pure (X509.CertificateChain certs, k) -- | Extract the private key and certificate chain from a 'PKCS12' value. A -- credential is returned when the structure contains exactly one private key -- and at least one X.509 certificate. toCredential :: PKCS12 -> OptProtected (Maybe (X509.CertificateChain, X509.PrivKey)) toCredential p12 = unSamePassword (SamePassword (unPKCS12 p12) >>= getInnerCredential) getInnerCredentialNamed :: String -> [SafeContents] -> SamePassword (Maybe (X509.CertificateChain, X509.PrivKey)) getInnerCredentialNamed name l = SamePassword (fn <$> getAllSafeKeys filtered) where certs = getAllSafeX509Certs l filtered = map (filterByFriendlyName name) l fn keys = do k <- single keys leaf <- single (getAllSafeX509Certs filtered) pure (buildCertificateChain leaf certs, k) -- | Extract a private key and certificate chain with the specified friendly -- name from a 'PKCS12' value. A credential is returned when the structure -- contains exactly one private key and one X.509 certificate with the name. toNamedCredential :: String -> PKCS12 -> OptProtected (Maybe (X509.CertificateChain, X509.PrivKey)) toNamedCredential name p12 = unSamePassword $ SamePassword (unPKCS12 p12) >>= getInnerCredentialNamed name -- | Build a 'PKCS12' value containing a private key and certificate chain. -- Distinct encryption is applied for both. Encrypting the certificate chain is -- optional. -- -- Note: advice is to always generate fresh and independent 'EncryptionScheme' -- values so that the salt is not reused twice in the encryption process. fromCredential :: Maybe EncryptionScheme -- for certificates -> EncryptionScheme -- for private key -> ProtectionPassword -> (X509.CertificateChain, X509.PrivKey) -> Either StoreError PKCS12 fromCredential = fromCredential' id -- | Build a 'PKCS12' value containing a private key and certificate chain -- identified with the specified friendly name. Distinct encryption is applied -- for private key and certificates. Encrypting the certificate chain is -- optional. -- -- Note: advice is to always generate fresh and independent 'EncryptionScheme' -- values so that the salt is not reused twice in the encryption process. fromNamedCredential :: String -> Maybe EncryptionScheme -- for certificates -> EncryptionScheme -- for private key -> ProtectionPassword -> (X509.CertificateChain, X509.PrivKey) -> Either StoreError PKCS12 fromNamedCredential name = fromCredential' (setFriendlyName name) fromCredential' :: ([Attribute] -> [Attribute]) -> Maybe EncryptionScheme -- for certificates -> EncryptionScheme -- for private key -> ProtectionPassword -> (X509.CertificateChain, X509.PrivKey) -> Either StoreError PKCS12 fromCredential' _ _ _ _ (X509.CertificateChain [], _) = Left (InvalidInput "Empty certificate chain") fromCredential' trans algChain algKey pwd (X509.CertificateChain certs@(leaf:_), key) = (<>) <$> pkcs12Chain <*> pkcs12Key where pkcs12Key = unencrypted <$> scKeyOrError pkcs12Chain = case algChain of Just alg -> encrypted alg pwd scChain Nothing -> Right (unencrypted scChain) scChain = SafeContents (zipWith toCertBag certAttrs certs) certAttrs = attrs : repeat [] toCertBag a c = Bag (CertBag (Bag (CertX509 c) [])) a scKeyOrError = wrap <$> encrypt algKey pwd encodedKey wrap shrouded = SafeContents [Bag (PKCS8ShroudedKeyBag shrouded) attrs] encodedKey = encodeASN1Object (FormattedKey PKCS8Format key) X509.Fingerprint keyId = X509.getFingerprint leaf X509.HashSHA1 attrs = trans (setLocalKeyId keyId []) -- Standard attributes friendlyName :: OID friendlyName = [1,2,840,113549,1,9,20] -- | Return the value of the @friendlyName@ attribute. getFriendlyName :: [Attribute] -> Maybe String getFriendlyName attrs = runParseAttribute friendlyName attrs $ do ASN1String str <- getNext case asn1CharacterToString str of Nothing -> throwParseError "Invalid friendlyName value" Just s -> return s -- | Add or replace the @friendlyName@ attribute in a list of attributes. setFriendlyName :: String -> [Attribute] -> [Attribute] setFriendlyName name = setAttributeASN1S friendlyName (gBMPString name) localKeyId :: OID localKeyId = [1,2,840,113549,1,9,21] -- | Return the value of the @localKeyId@ attribute. getLocalKeyId :: [Attribute] -> Maybe BS.ByteString getLocalKeyId attrs = runParseAttribute localKeyId attrs $ do OctetString d <- getNext return d -- | Add or replace the @localKeyId@ attribute in a list of attributes. setLocalKeyId :: BS.ByteString -> [Attribute] -> [Attribute] setLocalKeyId d = setAttributeASN1S localKeyId (gOctetString d) -- Utilities -- Internal wrapper of OptProtected providing Applicative and Monad instances. -- -- This adds the following constraint: all values composed must derive from the -- same encryption password. Semantically, 'Protected' actually means -- "requiring a password". Otherwise composition of 'Protected' and -- 'Unprotected' values is unsound. newtype SamePassword a = SamePassword { unSamePassword :: OptProtected a } instance Functor SamePassword where fmap f (SamePassword opt) = SamePassword (fmap f opt) instance Applicative SamePassword where pure a = SamePassword (Unprotected a) SamePassword (Unprotected f) <*> SamePassword (Unprotected x) = SamePassword (Unprotected (f x)) SamePassword (Unprotected f) <*> SamePassword (Protected x) = SamePassword $ Protected (fmap f . x) SamePassword (Protected f) <*> SamePassword (Unprotected x) = SamePassword $ Protected (fmap ($ x) . f) SamePassword (Protected f) <*> SamePassword (Protected x) = SamePassword $ Protected (\pwd -> f pwd <*> x pwd) instance Monad SamePassword where return = pure SamePassword (Unprotected x) >>= f = f x SamePassword (Protected inner) >>= f = SamePassword . Protected $ \pwd -> case inner pwd of Left err -> Left err Right x -> recover pwd (unSamePassword $ f x) applySamePassword :: [OptProtected a] -> OptProtected [a] applySamePassword = unSamePassword . traverse SamePassword single :: [a] -> Maybe a single [x] = Just x single _ = Nothing data Id a = Id { unId :: a , idKeyId :: Maybe BS.ByteString , idName :: Maybe String } mkId :: a -> Bag info -> Id a mkId val bag = val `seq` Id val (getLocalKeyId attrs) (getFriendlyName attrs) where attrs = bagAttributes bag decode :: ParseASN1Object [ASN1Event] obj => BS.ByteString -> Either StoreError obj decode = decodeASN1Object parseOctetStringObject :: (Monoid e, ParseASN1Object [ASN1Event] obj) => String -> ParseASN1 e obj parseOctetStringObject name = do bs <- parseOctetString case decode bs of Left e -> throwParseError (name ++ ": " ++ show e) Right c -> return c buildCertificateChain :: X509.SignedCertificate -> [X509.SignedCertificate] -> X509.CertificateChain buildCertificateChain leaf authorities = X509.CertificateChain (leaf : findAuthorities leaf authorities) where findAuthorities cert others | subject cert == issuer cert = [] | otherwise = case partition (\c -> subject c == issuer cert) others of ([c], others') -> c : findAuthorities c others' _ -> [] signedCert = X509.signedObject . X509.getSigned subject c = X509.certSubjectDN (signedCert c) issuer c = X509.certIssuerDN (signedCert c) cryptostore-0.3.1.0/src/Crypto/Store/PKCS5.hs0000644000000000000000000002457307346545000016776 0ustar0000000000000000-- | -- Module : Data.Store.PKCS5 -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- Password-Based Cryptography, aka PKCS #5. {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} module Crypto.Store.PKCS5 ( ProtectionPassword , emptyNotTerminated , fromProtectionPassword , toProtectionPassword , EncryptedContent -- * High-level API , PKCS5(..) , encrypt , decrypt -- * Encryption schemes , EncryptionScheme(..) , PBEParameter(..) , PBES2Parameter(..) -- * Key derivation , KeyDerivationFunc(..) , PBKDF2_PRF(..) , Salt , generateSalt -- * Content encryption , ContentEncryptionParams , ContentEncryptionAlg(..) , ContentEncryptionCipher(..) , generateEncryptionParams , getContentEncryptionAlg -- * Low-level API , pbEncrypt , pbDecrypt ) where import Data.ASN1.Types import Data.ByteString (ByteString) import Data.Maybe (fromMaybe) import Crypto.Store.ASN1.Parse import Crypto.Store.ASN1.Generate import Crypto.Store.CMS.Algorithms import Crypto.Store.CMS.Encrypted import Crypto.Store.CMS.Util import Crypto.Store.Error import Crypto.Store.PKCS5.PBES1 data EncryptionSchemeType = Type_PBES2 | Type_PBE_MD5_DES_CBC | Type_PBE_SHA1_DES_CBC | Type_PBE_SHA1_RC4_128 | Type_PBE_SHA1_RC4_40 | Type_PBE_SHA1_DES_EDE3_CBC | Type_PBE_SHA1_DES_EDE2_CBC | Type_PBE_SHA1_RC2_128 | Type_PBE_SHA1_RC2_40 instance Enumerable EncryptionSchemeType where values = [ Type_PBES2 , Type_PBE_MD5_DES_CBC , Type_PBE_SHA1_DES_CBC , Type_PBE_SHA1_RC4_128 , Type_PBE_SHA1_RC4_40 , Type_PBE_SHA1_DES_EDE3_CBC , Type_PBE_SHA1_DES_EDE2_CBC , Type_PBE_SHA1_RC2_128 , Type_PBE_SHA1_RC2_40 ] instance OIDable EncryptionSchemeType where getObjectID Type_PBES2 = [1,2,840,113549,1,5,13] getObjectID Type_PBE_MD5_DES_CBC = [1,2,840,113549,1,5,3] getObjectID Type_PBE_SHA1_DES_CBC = [1,2,840,113549,1,5,10] getObjectID Type_PBE_SHA1_RC4_128 = [1,2,840,113549,1,12,1,1] getObjectID Type_PBE_SHA1_RC4_40 = [1,2,840,113549,1,12,1,2] getObjectID Type_PBE_SHA1_DES_EDE3_CBC = [1,2,840,113549,1,12,1,3] getObjectID Type_PBE_SHA1_DES_EDE2_CBC = [1,2,840,113549,1,12,1,4] getObjectID Type_PBE_SHA1_RC2_128 = [1,2,840,113549,1,12,1,5] getObjectID Type_PBE_SHA1_RC2_40 = [1,2,840,113549,1,12,1,6] instance OIDNameable EncryptionSchemeType where fromObjectID oid = unOIDNW <$> fromObjectID oid -- | Password-Based Encryption Scheme (PBES). data EncryptionScheme = PBES2 PBES2Parameter -- ^ PBES2 | PBE_MD5_DES_CBC PBEParameter -- ^ pbeWithMD5AndDES-CBC | PBE_SHA1_DES_CBC PBEParameter -- ^ pbeWithSHA1AndDES-CBC | PBE_SHA1_RC4_128 PBEParameter -- ^ pbeWithSHAAnd128BitRC4 | PBE_SHA1_RC4_40 PBEParameter -- ^ pbeWithSHAAnd40BitRC4 | PBE_SHA1_DES_EDE3_CBC PBEParameter -- ^ pbeWithSHAAnd3-KeyTripleDES-CBC | PBE_SHA1_DES_EDE2_CBC PBEParameter -- ^ pbeWithSHAAnd2-KeyTripleDES-CBC | PBE_SHA1_RC2_128 PBEParameter -- ^ pbeWithSHAAnd128BitRC2-CBC | PBE_SHA1_RC2_40 PBEParameter -- ^ pbewithSHAAnd40BitRC2-CBC deriving (Show,Eq) -- | PBES2 parameters. data PBES2Parameter = PBES2Parameter { pbes2KDF :: KeyDerivationFunc -- ^ Key derivation function , pbes2EScheme :: ContentEncryptionParams -- ^ Underlying encryption scheme } deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e PBES2Parameter where asn1s PBES2Parameter{..} = let kdFunc = algorithmASN1S Sequence pbes2KDF eScheme = asn1s pbes2EScheme in asn1Container Sequence (kdFunc . eScheme) instance Monoid e => ParseASN1Object e PBES2Parameter where parse = onNextContainer Sequence $ do kdFunc <- parseAlgorithm Sequence eScheme <- parse case kdfKeyLength kdFunc of Nothing -> return () Just sz | validateKeySize eScheme sz -> return () | otherwise -> throwParseError "PBES2Parameter: parsed key length incompatible with encryption scheme" return PBES2Parameter { pbes2KDF = kdFunc, pbes2EScheme = eScheme } instance AlgorithmId EncryptionScheme where type AlgorithmType EncryptionScheme = EncryptionSchemeType algorithmName _ = "encryption scheme" algorithmType (PBES2 _) = Type_PBES2 algorithmType (PBE_MD5_DES_CBC _) = Type_PBE_MD5_DES_CBC algorithmType (PBE_SHA1_DES_CBC _) = Type_PBE_SHA1_DES_CBC algorithmType (PBE_SHA1_RC4_128 _) = Type_PBE_SHA1_RC4_128 algorithmType (PBE_SHA1_RC4_40 _) = Type_PBE_SHA1_RC4_40 algorithmType (PBE_SHA1_DES_EDE3_CBC _) = Type_PBE_SHA1_DES_EDE3_CBC algorithmType (PBE_SHA1_DES_EDE2_CBC _) = Type_PBE_SHA1_DES_EDE2_CBC algorithmType (PBE_SHA1_RC2_128 _) = Type_PBE_SHA1_RC2_128 algorithmType (PBE_SHA1_RC2_40 _) = Type_PBE_SHA1_RC2_40 parameterASN1S (PBES2 p) = asn1s p parameterASN1S (PBE_MD5_DES_CBC p) = asn1s p parameterASN1S (PBE_SHA1_DES_CBC p) = asn1s p parameterASN1S (PBE_SHA1_RC4_128 p) = asn1s p parameterASN1S (PBE_SHA1_RC4_40 p) = asn1s p parameterASN1S (PBE_SHA1_DES_EDE3_CBC p) = asn1s p parameterASN1S (PBE_SHA1_DES_EDE2_CBC p) = asn1s p parameterASN1S (PBE_SHA1_RC2_128 p) = asn1s p parameterASN1S (PBE_SHA1_RC2_40 p) = asn1s p parseParameter Type_PBES2 = PBES2 <$> parse parseParameter Type_PBE_MD5_DES_CBC = PBE_MD5_DES_CBC <$> parse parseParameter Type_PBE_SHA1_DES_CBC = PBE_SHA1_DES_CBC <$> parse parseParameter Type_PBE_SHA1_RC4_128 = PBE_SHA1_RC4_128 <$> parse parseParameter Type_PBE_SHA1_RC4_40 = PBE_SHA1_RC4_40 <$> parse parseParameter Type_PBE_SHA1_DES_EDE3_CBC = PBE_SHA1_DES_EDE3_CBC <$> parse parseParameter Type_PBE_SHA1_DES_EDE2_CBC = PBE_SHA1_DES_EDE2_CBC <$> parse parseParameter Type_PBE_SHA1_RC2_128 = PBE_SHA1_RC2_128 <$> parse parseParameter Type_PBE_SHA1_RC2_40 = PBE_SHA1_RC2_40 <$> parse instance ASN1Elem e => ProduceASN1Object e EncryptionScheme where asn1s = algorithmASN1S Sequence instance Monoid e => ParseASN1Object e EncryptionScheme where parse = parseAlgorithm Sequence -- High-level API -- | Content encrypted with a Password-Based Encryption Scheme (PBES). -- -- The content will usually be the binary representation of an ASN.1 object, -- however the transformation may be applied to any bytestring. data PKCS5 = PKCS5 { encryptionAlgorithm :: EncryptionScheme -- ^ Scheme used to encrypt content , encryptedData :: EncryptedContent -- ^ Encrypted content } deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e PKCS5 where asn1s PKCS5{..} = asn1Container Sequence (alg . bs) where alg = asn1s encryptionAlgorithm bs = gOctetString encryptedData instance Monoid e => ParseASN1Object e PKCS5 where parse = onNextContainer Sequence $ do alg <- parse OctetString bs <- getNext return PKCS5 { encryptionAlgorithm = alg, encryptedData = bs } instance ASN1Object PKCS5 where toASN1 = asn1s fromASN1 = runParseASN1State parse -- | Encrypt a bytestring with the specified encryption scheme and password. encrypt :: EncryptionScheme -> ProtectionPassword -> ByteString -> Either StoreError PKCS5 encrypt alg pwd bs = build <$> pbEncrypt alg bs pwd where build ed = ed `seq` PKCS5 { encryptionAlgorithm = alg, encryptedData = ed } -- | Decrypt the PKCS #5 content with the specified password. decrypt :: PKCS5 -> ProtectionPassword -> Either StoreError ByteString decrypt obj = pbDecrypt (encryptionAlgorithm obj) (encryptedData obj) -- Encryption Schemes -- | Encrypt a bytestring with the specified encryption scheme and password. pbEncrypt :: EncryptionScheme -> ByteString -> ProtectionPassword -> Either StoreError EncryptedContent pbEncrypt (PBES2 p) = pbes2 contentEncrypt p pbEncrypt (PBE_MD5_DES_CBC p) = pkcs5 Left contentEncrypt MD5 DES p pbEncrypt (PBE_SHA1_DES_CBC p) = pkcs5 Left contentEncrypt SHA1 DES p pbEncrypt (PBE_SHA1_RC4_128 p) = pkcs12stream Left rc4Combine SHA1 16 p pbEncrypt (PBE_SHA1_RC4_40 p) = pkcs12stream Left rc4Combine SHA1 5 p pbEncrypt (PBE_SHA1_DES_EDE3_CBC p) = pkcs12 Left contentEncrypt SHA1 DES_EDE3 p pbEncrypt (PBE_SHA1_DES_EDE2_CBC p) = pkcs12 Left contentEncrypt SHA1 DES_EDE2 p pbEncrypt (PBE_SHA1_RC2_128 p) = pkcs12rc2 Left contentEncrypt SHA1 128 p pbEncrypt (PBE_SHA1_RC2_40 p) = pkcs12rc2 Left contentEncrypt SHA1 40 p -- | Decrypt an encrypted bytestring with the specified encryption scheme and -- password. pbDecrypt :: EncryptionScheme -> EncryptedContent -> ProtectionPassword -> Either StoreError ByteString pbDecrypt (PBES2 p) = pbes2 contentDecrypt p pbDecrypt (PBE_MD5_DES_CBC p) = pkcs5 Left contentDecrypt MD5 DES p pbDecrypt (PBE_SHA1_DES_CBC p) = pkcs5 Left contentDecrypt SHA1 DES p pbDecrypt (PBE_SHA1_RC4_128 p) = pkcs12stream Left rc4Combine SHA1 16 p pbDecrypt (PBE_SHA1_RC4_40 p) = pkcs12stream Left rc4Combine SHA1 5 p pbDecrypt (PBE_SHA1_DES_EDE3_CBC p) = pkcs12 Left contentDecrypt SHA1 DES_EDE3 p pbDecrypt (PBE_SHA1_DES_EDE2_CBC p) = pkcs12 Left contentDecrypt SHA1 DES_EDE2 p pbDecrypt (PBE_SHA1_RC2_128 p) = pkcs12rc2 Left contentDecrypt SHA1 128 p pbDecrypt (PBE_SHA1_RC2_40 p) = pkcs12rc2 Left contentDecrypt SHA1 40 p pbes2 :: (Key -> ContentEncryptionParams -> ByteString -> result) -> PBES2Parameter -> ByteString -> ProtectionPassword -> result pbes2 encdec PBES2Parameter{..} bs pwd = encdec key pbes2EScheme bs where key = kdfDerive pbes2KDF len (fromProtectionPassword pwd) :: Key len = fromMaybe (getMaximumKeySize pbes2EScheme) (kdfKeyLength pbes2KDF) cryptostore-0.3.1.0/src/Crypto/Store/PKCS5/0000755000000000000000000000000007346545000016427 5ustar0000000000000000cryptostore-0.3.1.0/src/Crypto/Store/PKCS5/PBES1.hs0000644000000000000000000003523307346545000017603 0ustar0000000000000000-- | -- Module : Data.Store.PKCS5.PBES1 -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- Password-Based Encryption Schemes {-# LANGUAGE BangPatterns #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-} module Crypto.Store.PKCS5.PBES1 ( PBEParameter(..) , Key , ProtectionPassword , emptyNotTerminated , fromProtectionPassword , toProtectionPassword , toProtectionPasswords , pkcs5 , pkcs12 , pkcs12rc2 , pkcs12stream , pkcs12mac , rc4Combine ) where import Basement.Block (Block) import Basement.Compat.IsList import Basement.Endianness import qualified Basement.String as S import Crypto.Cipher.Types import qualified Crypto.Cipher.RC4 as RC4 import qualified Crypto.Hash as Hash import Data.ASN1.Types import Data.Bits import Data.ByteArray (ByteArray, ByteArrayAccess) import qualified Data.ByteArray as B import Data.ByteString (ByteString) import Data.Maybe (fromMaybe) import Data.Memory.PtrMethods import Data.String (IsString(..)) import Data.Word import Foreign.Ptr (plusPtr) import Foreign.Storable import Crypto.Store.ASN1.Parse import Crypto.Store.ASN1.Generate import Crypto.Store.CMS.Algorithms import Crypto.Store.CMS.Util import Crypto.Store.Error -- | A password stored as a sequence of UTF-8 bytes. -- -- Some key-derivation functions add restrictions to what characters -- are supported. -- -- The data type provides a special value 'emptyNotTerminated' that is used -- as alternate representation of empty passwords on some systems and that -- produces encryption results different than an empty bytearray. -- -- Conversion to/from a regular sequence of bytes is possible with functions -- 'toProtectionPassword' and 'fromProtectionPassword'. -- -- Beware: the 'fromString' implementation correctly handles multi-byte -- characters, so here is not equivalent to the 'ByteString' counterpart. data ProtectionPassword = NullPassword | PasswordUTF8 ByteString deriving Eq instance Show ProtectionPassword where showsPrec _ NullPassword = showString "emptyNotTerminated" showsPrec d (PasswordUTF8 b) = showParen (d > 10) $ showString "toProtectionPassword " . showsPrec 11 b instance IsString ProtectionPassword where fromString = PasswordUTF8 . B.convert . S.toBytes S.UTF8 . fromString instance ByteArrayAccess ProtectionPassword where length = applyPP 0 B.length withByteArray = B.withByteArray . fromProtectionPassword applyPP :: a -> (ByteString -> a) -> ProtectionPassword -> a applyPP d _ NullPassword = d applyPP _ f (PasswordUTF8 b) = f b -- | A value denoting an empty password, but having a special encoding when -- deriving a symmetric key on some systems, like the certificate export -- wizard on Windows. -- -- This value is different from @'toProtectionPassword' ""@ and can be tried -- when decrypting content with a password known to be empty. emptyNotTerminated :: ProtectionPassword emptyNotTerminated = NullPassword -- | Extract the UTF-8 bytes in a password value. fromProtectionPassword :: ProtectionPassword -> ByteString fromProtectionPassword = applyPP B.empty id -- | Build a password value from a sequence of UTF-8 bytes. -- -- When the password is empty, the special value 'emptyNotTerminated' may -- be tried as well. toProtectionPassword :: ByteString -> ProtectionPassword toProtectionPassword = PasswordUTF8 toProtectionPasswords :: ByteString -> [ProtectionPassword] toProtectionPasswords bs | B.null bs = [PasswordUTF8 B.empty, NullPassword] | otherwise = [PasswordUTF8 bs] -- | Secret key. type Key = B.ScrubbedBytes -- | PBES1 parameters. data PBEParameter = PBEParameter { pbeSalt :: Salt -- ^ 8-octet salt value , pbeIterationCount :: Int -- ^ Iteration count } deriving (Show,Eq) instance ASN1Elem e => ProduceASN1Object e PBEParameter where asn1s PBEParameter{..} = let salt = gOctetString pbeSalt iters = gIntVal (toInteger pbeIterationCount) in asn1Container Sequence (salt . iters) instance Monoid e => ParseASN1Object e PBEParameter where parse = onNextContainer Sequence $ do OctetString salt <- getNext IntVal iters <- getNext return PBEParameter { pbeSalt = salt , pbeIterationCount = fromInteger iters } cbcWith :: (BlockCipher cipher, ByteArrayAccess iv) => ContentEncryptionCipher cipher -> iv -> ContentEncryptionParams cbcWith cipher iv = ParamsCBC cipher getIV where getIV = fromMaybe (error "PKCS5: bad initialization vector") (makeIV iv) rc2cbcWith :: ByteArrayAccess iv => Int -> iv -> ContentEncryptionParams rc2cbcWith len iv = ParamsCBCRC2 len getIV where getIV = fromMaybe (error "PKCS5: bad RC2 initialization vector") (makeIV iv) -- | RC4 encryption or decryption. rc4Combine :: (ByteArrayAccess key, ByteArray ba) => key -> ba -> Either StoreError ba rc4Combine key = Right . snd . RC4.combine (RC4.initialize key) -- | Conversion to UCS2 from UTF-8, ignoring non-BMP bits. toUCS2 :: ByteArray bucs2 => ProtectionPassword -> Maybe bucs2 toUCS2 NullPassword = Just B.empty toUCS2 (PasswordUTF8 pwdUTF8) | B.null r = Just pwdUCS2 | otherwise = Nothing where (p, _, r) = S.fromBytes S.UTF8 $ B.snoc (B.convert pwdUTF8) 0 pwdBlock = fromList $ map ucs2 $ toList p :: Block (BE Word16) pwdUCS2 = B.convert pwdBlock ucs2 :: Char -> BE Word16 ucs2 = toBE . toEnum . fromEnum -- PBES1, RFC 8018 section 6.1.2 -- | Apply PBKDF1 on the specified password and run an encryption or decryption -- function on some input using derived key and IV. pkcs5 :: (Hash.HashAlgorithm hash, BlockCipher cipher) => (StoreError -> result) -> (Key -> ContentEncryptionParams -> ByteString -> result) -> DigestProxy hash -> ContentEncryptionCipher cipher -> PBEParameter -> ByteString -> ProtectionPassword -> result pkcs5 failure encdec hashAlg cec pbeParam bs pwd | proxyBlockSize cec /= 8 = failure (InvalidParameter "Invalid cipher block size") | otherwise = case pbkdf1 hashAlg (fromProtectionPassword pwd) pbeParam 16 of Left err -> failure err Right dk -> let (key, iv) = B.splitAt 8 (dk :: Key) in encdec key (cbcWith cec iv) bs -- PBKDF1, RFC 8018 section 5.1 pbkdf1 :: (Hash.HashAlgorithm hash, ByteArrayAccess password, ByteArray out) => DigestProxy hash -> password -> PBEParameter -> Int -> Either StoreError out pbkdf1 hashAlg pwd PBEParameter{..} dkLen | dkLen > B.length t1 = Left (InvalidParameter "Derived key too long") | otherwise = Right (B.convert $ B.takeView tc dkLen) where a = hashFromProxy hashAlg t1 = Hash.hashFinalize (Hash.hashUpdate (Hash.hashUpdate (Hash.hashInitWith a) pwd) pbeSalt) tc = iterate (Hash.hashWith a) t1 !! pred pbeIterationCount -- PKCS#12 encryption, RFC 7292 appendix B.2 -- | Apply PKCS #12 derivation on the specified password and run an encryption -- or decryption function on some input using derived key and IV. pkcs12 :: (Hash.HashAlgorithm hash, BlockCipher cipher) => (StoreError -> result) -> (Key -> ContentEncryptionParams -> ByteString -> result) -> DigestProxy hash -> ContentEncryptionCipher cipher -> PBEParameter -> ByteString -> ProtectionPassword -> result pkcs12 failure encdec hashAlg cec pbeParam bs pwdUTF8 = case toUCS2 pwdUTF8 of Nothing -> failure passwordNotUTF8 Just pwdUCS2 -> let ivLen = proxyBlockSize cec iv = pkcs12Derive hashAlg pbeParam 2 pwdUCS2 ivLen :: B.Bytes eScheme = cbcWith cec iv keyLen = getMaximumKeySize eScheme key = pkcs12Derive hashAlg pbeParam 1 pwdUCS2 keyLen :: Key in encdec key eScheme bs -- | Apply PKCS #12 derivation on the specified password and run an encryption -- or decryption function on some input using derived key and IV. This variant -- uses an RC2 cipher with the EKL specified (effective key length). pkcs12rc2 :: Hash.HashAlgorithm hash => (StoreError -> result) -> (Key -> ContentEncryptionParams -> ByteString -> result) -> DigestProxy hash -> Int -> PBEParameter -> ByteString -> ProtectionPassword -> result pkcs12rc2 failure encdec hashAlg len pbeParam bs pwdUTF8 = case toUCS2 pwdUTF8 of Nothing -> failure passwordNotUTF8 Just pwdUCS2 -> let ivLen = 8 iv = pkcs12Derive hashAlg pbeParam 2 pwdUCS2 ivLen :: B.Bytes eScheme = rc2cbcWith len iv keyLen = getMaximumKeySize eScheme key = pkcs12Derive hashAlg pbeParam 1 pwdUCS2 keyLen :: Key in encdec key eScheme bs -- | Apply PKCS #12 derivation on the specified password and run an encryption -- or decryption function on some input using derived key. This variant does -- not derive any IV and is required for RC4. pkcs12stream :: Hash.HashAlgorithm hash => (StoreError -> result) -> (Key -> ByteString -> result) -> DigestProxy hash -> Int -> PBEParameter -> ByteString -> ProtectionPassword -> result pkcs12stream failure encdec hashAlg keyLen pbeParam bs pwdUTF8 = case toUCS2 pwdUTF8 of Nothing -> failure passwordNotUTF8 Just pwdUCS2 -> let key = pkcs12Derive hashAlg pbeParam 1 pwdUCS2 keyLen :: Key in encdec key bs -- | Apply PKCS #12 derivation on the specified password and run a MAC function -- on some input using derived key. pkcs12mac :: Hash.HashAlgorithm hash => (StoreError -> result) -> (Key -> MACAlgorithm -> ByteString -> result) -> DigestProxy hash -> PBEParameter -> ByteString -> ProtectionPassword -> result pkcs12mac failure macFn hashAlg pbeParam bs pwdUTF8 = case toUCS2 pwdUTF8 of Nothing -> failure passwordNotUTF8 Just pwdUCS2 -> let macAlg = HMAC hashAlg keyLen = getMaximumKeySize macAlg key = pkcs12Derive hashAlg pbeParam 3 pwdUCS2 keyLen :: Key in macFn key macAlg bs passwordNotUTF8 :: StoreError passwordNotUTF8 = InvalidPassword "Provided password is not valid UTF-8" pkcs12Derive :: (Hash.HashAlgorithm hash, ByteArray bout) => DigestProxy hash -> PBEParameter -> Word8 -> ByteString -- password (UCS2) -> Int -> bout pkcs12Derive hashAlg PBEParameter{..} idByte pwdUCS2 n = B.take n $ B.concat $ take c $ loop t (s `B.append` p) where a = hashFromProxy hashAlg v = getV (DigestAlgorithm hashAlg) u = Hash.hashDigestSize a c = (n + u - 1) `div` u d = B.replicate v idByte :: B.Bytes t = Hash.hashUpdate (Hash.hashInitWith a) d p = pwdUCS2 `extendedToMult` v s = pbeSalt `extendedToMult` v loop :: Hash.HashAlgorithm hash => Hash.Context hash -> ByteString -> [Hash.Digest hash] loop x i = let z = Hash.hashFinalize (Hash.hashUpdate x i) ai = iterate Hash.hash z !! pred pbeIterationCount b = ai `extendedTo` v j = B.concat $ map (add1 b) (chunks v i) in ai : loop x j getV :: DigestAlgorithm -> Int getV (DigestAlgorithm MD2) = 64 getV (DigestAlgorithm MD4) = 64 getV (DigestAlgorithm MD5) = 64 getV (DigestAlgorithm SHA1) = 64 getV (DigestAlgorithm SHA224) = 64 getV (DigestAlgorithm SHA256) = 64 getV (DigestAlgorithm SHA384) = 128 getV (DigestAlgorithm SHA512) = 128 getV t = error ("pkcs12Derive: unsupported hash: " ++ show t) hashFromProxy :: proxy a -> a hashFromProxy _ = undefined -- Split in chunks of size 'n' chunks :: ByteArray ba => Int -> ba -> [ba] chunks n bs | len > n = let (c, cs) = B.splitAt n bs in c : chunks n cs | len > 0 = [bs] | otherwise = [] where len = B.length bs -- Concatenate copies of input 'bs' to create output of length 'n' -- bytes (the final copy may be truncated) extendedTo :: (ByteArrayAccess bin, ByteArray bout) => bin -> Int -> bout bs `extendedTo` n = B.allocAndFreeze n $ \pout -> B.withByteArray bs $ \pin -> do mapM_ (\off -> memCopy (pout `plusPtr` off) pin len) (enumFromThenTo 0 len (n - len)) memCopy (pout `plusPtr` (n - r)) pin r where len = B.length bs r = n `mod` len {-# NOINLINE extendedTo #-} -- Concatenate copies of input 'bs' to create output whose length is a -- multiple of 'n' bytes (the final copy may be truncated). If input -- is the empty string, so is the output. extendedToMult :: ByteArray ba => ba -> Int -> ba bs `extendedToMult` n | len > n = bs `B.append` B.take (n - len `mod` n) bs | len == n = bs | len > 0 = bs `extendedTo` n | otherwise = B.empty where len = B.length bs -- Add two bytearrays (considered as big-endian integers) and increment the -- result. Output has size of the first bytearray. add1 :: ByteString -> ByteString -> ByteString add1 a b = B.allocAndFreeze alen $ \pc -> B.withByteArray a $ \pa -> B.withByteArray b $ \pb -> loop3 pa pb pc alen blen 1 where alen = B.length a blen = B.length b -- main loop when both 'a' and 'b' have remaining bytes loop3 !pa !pb !pc !ma !mb !c | ma == 0 = return () | mb == 0 = loop2 pa pc ma c | otherwise = do let na = pred ma nb = pred mb ba <- peekElemOff pa na bb <- peekElemOff pb nb let (cc, bc) = carryAdd3 c ba bb pokeElemOff pc na bc loop3 pa pb pc na nb cc -- when 'b' is smaller and bytes are exhausted we propagate -- carry on 'a' alone loop2 !pa !pc !ma !c | ma == 0 = return () | otherwise = do let na = pred ma ba <- peekElemOff pa na let (cc, bc) = carryAdd2 c ba pokeElemOff pc na bc loop2 pa pc na cc split16 :: Word16 -> (Word8, Word8) split16 x = (fromIntegral (shiftR x 8), fromIntegral x) carryAdd2 :: Word8 -> Word8 -> (Word8, Word8) carryAdd2 a b = split16 (fromIntegral a + fromIntegral b) carryAdd3 :: Word8 -> Word8 -> Word8 -> (Word8, Word8) carryAdd3 a b c = split16 (fromIntegral a + fromIntegral b + fromIntegral c) cryptostore-0.3.1.0/src/Crypto/Store/PKCS8.hs0000644000000000000000000006660607346545000017004 0ustar0000000000000000-- | -- Module : Crypto.Store.PKCS8 -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- Private-Key Information Syntax, aka PKCS #8. -- -- Presents an API similar to "Data.X509.Memory" and "Data.X509.File" but -- allows to write private keys and provides support for password-based -- encryption. -- -- Functions to read a private key return an object wrapped in the -- 'OptProtected' data type. -- -- Functions related to public keys, certificates and CRLs are available from -- "Crypto.Store.X509". {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE UndecidableInstances #-} module Crypto.Store.PKCS8 ( readKeyFile , readKeyFileFromMemory , pemToKey , writeKeyFile , writeKeyFileToMemory , keyToPEM , writeEncryptedKeyFile , writeEncryptedKeyFileToMemory , encryptKeyToPEM -- * Serialization formats , PrivateKeyFormat(..) , FormattedKey(..) -- * Password-based protection , ProtectionPassword , emptyNotTerminated , fromProtectionPassword , toProtectionPassword , OptProtected(..) , recover , recoverA -- * Reading and writing PEM files , readPEMs , writePEMs ) where import Control.Applicative import Control.Monad (void, when) import Data.ASN1.Types import Data.ASN1.BinaryEncoding import Data.ASN1.BitArray import Data.ASN1.Encoding import Data.ByteArray (ByteArrayAccess, convert) import Data.Maybe import qualified Data.X509 as X509 import qualified Data.ByteString as B import Crypto.Error import Crypto.Number.Serialize (i2osp, i2ospOf_, os2ip) import qualified Crypto.PubKey.Curve25519 as X25519 import qualified Crypto.PubKey.Curve448 as X448 import qualified Crypto.PubKey.DSA as DSA import qualified Crypto.PubKey.ECC.ECDSA as ECDSA import qualified Crypto.PubKey.Ed25519 as Ed25519 import qualified Crypto.PubKey.Ed448 as Ed448 import qualified Crypto.PubKey.RSA as RSA import Crypto.Store.ASN1.Generate import Crypto.Store.ASN1.Parse import Crypto.Store.CMS.Attribute import Crypto.Store.CMS.Util import Crypto.Store.Error import Crypto.Store.PEM import Crypto.Store.PKCS5 import Crypto.Store.PKCS8.EC import Crypto.Store.Util -- | Data type for objects that are possibly protected with a password. data OptProtected a = Unprotected a -- ^ Value is unprotected | Protected (ProtectionPassword -> Either StoreError a) -- ^ Value is protected with a password instance Functor OptProtected where fmap f (Unprotected x) = Unprotected (f x) fmap f (Protected g) = Protected (fmap f . g) -- | Try to recover an 'OptProtected' content using the specified password. recover :: ProtectionPassword -> OptProtected a -> Either StoreError a recover _ (Unprotected x) = Right x recover pwd (Protected f) = f pwd -- | Try to recover an 'OptProtected' content in an applicative context. The -- applicative password is used if necessary. -- -- > import qualified Data.ByteString as B -- > import Crypto.Store.PKCS8 -- > -- > [encryptedKey] <- readKeyFile "privkey.pem" -- > let askForPassword = putStr "Please enter password: " >> B.getLine -- > result <- recoverA (toProtectionPassword <$> askForPassword) encryptedKey -- > case result of -- > Left err -> putStrLn $ "Unable to recover key: " ++ show err -- > Right key -> print key recoverA :: Applicative f => f ProtectionPassword -> OptProtected a -> f (Either StoreError a) recoverA _ (Unprotected x) = pure (Right x) recoverA get (Protected f) = fmap f get -- Reading from PEM format -- | Read private keys from a PEM file. readKeyFile :: FilePath -> IO [OptProtected X509.PrivKey] readKeyFile path = accumulate <$> readPEMs path -- | Read private keys from a bytearray in PEM format. readKeyFileFromMemory :: B.ByteString -> [OptProtected X509.PrivKey] readKeyFileFromMemory = either (const []) accumulate . pemParseBS accumulate :: [PEM] -> [OptProtected X509.PrivKey] accumulate = catMaybes . foldr (flip pemToKey) [] -- | Read a private key from a 'PEM' element and add it to the accumulator list. pemToKey :: [Maybe (OptProtected X509.PrivKey)] -> PEM -> [Maybe (OptProtected X509.PrivKey)] pemToKey acc pem = case decodeASN1' BER (pemContent pem) of Left _ -> acc Right asn1 -> run (getParser $ pemName pem) asn1 : acc where run p = either (const Nothing) Just . runParseASN1 p allTypes = unFormat <$> parse rsa = X509.PrivKeyRSA . unFormat <$> parse dsa = X509.PrivKeyDSA . DSA.toPrivateKey . unFormat <$> parse ecdsa = X509.PrivKeyEC . unFormat <$> parse x25519 = X509.PrivKeyX25519 <$> parseModern x448 = X509.PrivKeyX448 <$> parseModern ed25519 = X509.PrivKeyEd25519 <$> parseModern ed448 = X509.PrivKeyEd448 <$> parseModern encrypted = inner . decrypt <$> parse getParser "PRIVATE KEY" = Unprotected <$> allTypes getParser "RSA PRIVATE KEY" = Unprotected <$> rsa getParser "DSA PRIVATE KEY" = Unprotected <$> dsa getParser "EC PRIVATE KEY" = Unprotected <$> ecdsa getParser "X25519 PRIVATE KEY" = Unprotected <$> x25519 getParser "X448 PRIVATE KEY" = Unprotected <$> x448 getParser "ED25519 PRIVATE KEY" = Unprotected <$> ed25519 getParser "ED448 PRIVATE KEY" = Unprotected <$> ed448 getParser "ENCRYPTED PRIVATE KEY" = Protected <$> encrypted getParser _ = empty inner decfn pwd = do decrypted <- decfn pwd asn1 <- mapLeft DecodingError $ decodeASN1' BER decrypted case run allTypes asn1 of Nothing -> Left (ParseFailure "No key parsed after decryption") Just k -> return k -- Writing to PEM format -- | Write unencrypted private keys to a PEM file. writeKeyFile :: PrivateKeyFormat -> FilePath -> [X509.PrivKey] -> IO () writeKeyFile fmt path = writePEMs path . map (keyToPEM fmt) -- | Write unencrypted private keys to a bytearray in PEM format. writeKeyFileToMemory :: PrivateKeyFormat -> [X509.PrivKey] -> B.ByteString writeKeyFileToMemory fmt = pemsWriteBS . map (keyToPEM fmt) -- | Write a PKCS #8 encrypted private key to a PEM file. -- -- If multiple keys need to be stored in the same file, use functions -- 'encryptKeyToPEM' and 'writePEMs'. -- -- Fresh 'EncryptionScheme' parameters should be generated for each key to -- encrypt. writeEncryptedKeyFile :: FilePath -> EncryptionScheme -> ProtectionPassword -> X509.PrivKey -> IO (Either StoreError ()) writeEncryptedKeyFile path alg pwd privKey = let pem = encryptKeyToPEM alg pwd privKey in either (return . Left) (fmap Right . writePEMs path . (:[])) pem -- | Write a PKCS #8 encrypted private key to a bytearray in PEM format. -- -- If multiple keys need to be stored in the same bytearray, use functions -- 'encryptKeyToPEM' and 'pemWriteBS' or 'pemWriteLBS'. -- -- Fresh 'EncryptionScheme' parameters should be generated for each key to -- encrypt. writeEncryptedKeyFileToMemory :: EncryptionScheme -> ProtectionPassword -> X509.PrivKey -> Either StoreError B.ByteString writeEncryptedKeyFileToMemory alg pwd privKey = pemWriteBS <$> encryptKeyToPEM alg pwd privKey -- | Generate an unencrypted PEM for a private key. keyToPEM :: PrivateKeyFormat -> X509.PrivKey -> PEM keyToPEM TraditionalFormat = keyToTraditionalPEM keyToPEM PKCS8Format = keyToModernPEM keyToTraditionalPEM :: X509.PrivKey -> PEM keyToTraditionalPEM privKey = mkPEM (typeTag ++ " PRIVATE KEY") (encodeASN1S asn1) where (typeTag, asn1) = traditionalPrivKeyASN1S privKey traditionalPrivKeyASN1S :: ASN1Elem e => X509.PrivKey -> (String, ASN1Stream e) traditionalPrivKeyASN1S privKey = case privKey of X509.PrivKeyRSA k -> ("RSA", traditional k) X509.PrivKeyDSA k -> ("DSA", traditional (dsaPrivToPair k)) X509.PrivKeyEC k -> ("EC", traditional k) X509.PrivKeyX25519 k -> ("X25519", tradModern k) X509.PrivKeyX448 k -> ("X448", tradModern k) X509.PrivKeyEd25519 k -> ("ED25519", tradModern k) X509.PrivKeyEd448 k -> ("ED448", tradModern k) where traditional a = asn1s (Traditional a) tradModern a = asn1s (Modern [] a) keyToModernPEM :: X509.PrivKey -> PEM keyToModernPEM privKey = mkPEM "PRIVATE KEY" (encodeASN1S asn1) where asn1 = modernPrivKeyASN1S [] privKey modernPrivKeyASN1S :: ASN1Elem e => [Attribute] -> X509.PrivKey -> ASN1Stream e modernPrivKeyASN1S attrs privKey = case privKey of X509.PrivKeyRSA k -> modern k X509.PrivKeyDSA k -> modern (dsaPrivToPair k) X509.PrivKeyEC k -> modern k X509.PrivKeyX25519 k -> modern k X509.PrivKeyX448 k -> modern k X509.PrivKeyEd25519 k -> modern k X509.PrivKeyEd448 k -> modern k where modern a = asn1s (Modern attrs a) -- | Generate a PKCS #8 encrypted PEM for a private key. -- -- Fresh 'EncryptionScheme' parameters should be generated for each key to -- encrypt. encryptKeyToPEM :: EncryptionScheme -> ProtectionPassword -> X509.PrivKey -> Either StoreError PEM encryptKeyToPEM alg pwd privKey = toPEM <$> encrypt alg pwd bs where bs = pemContent (keyToModernPEM privKey) toPEM pkcs8 = mkPEM "ENCRYPTED PRIVATE KEY" (encodeASN1Object pkcs8) mkPEM :: String -> B.ByteString -> PEM mkPEM name bs = PEM { pemName = name, pemHeader = [], pemContent = bs} -- Private key formats: traditional (SSLeay compatible) and modern (PKCS #8) -- | Private-key serialization format. -- -- Encryption in traditional format is not supported currently. data PrivateKeyFormat = TraditionalFormat -- ^ SSLeay compatible | PKCS8Format -- ^ PKCS #8 deriving (Show,Eq) newtype Traditional a = Traditional { unTraditional :: a } parseTraditional :: ParseASN1Object e (Traditional a) => ParseASN1 e a parseTraditional = unTraditional <$> parse data Modern a = Modern [Attribute] a instance Functor Modern where fmap f (Modern attrs a) = Modern attrs (f a) parseModern :: ParseASN1Object e (Modern a) => ParseASN1 e a parseModern = unModern <$> parse where unModern (Modern _ a) = a -- | A key associated with format. Allows to implement 'ASN1Object' instances. data FormattedKey a = FormattedKey PrivateKeyFormat a deriving (Show,Eq) instance Functor FormattedKey where fmap f (FormattedKey fmt a) = FormattedKey fmt (f a) instance (ProduceASN1Object e (Traditional a), ProduceASN1Object e (Modern a)) => ProduceASN1Object e (FormattedKey a) where asn1s (FormattedKey TraditionalFormat k) = asn1s (Traditional k) asn1s (FormattedKey PKCS8Format k) = asn1s (Modern [] k) instance (Monoid e, ParseASN1Object e (Traditional a), ParseASN1Object e (Modern a)) => ParseASN1Object e (FormattedKey a) where parse = (modern <$> parseModern) <|> (traditional <$> parseTraditional) where traditional = FormattedKey TraditionalFormat modern = FormattedKey PKCS8Format unFormat :: FormattedKey a -> a unFormat (FormattedKey _ a) = a -- Private Keys instance ASN1Object (FormattedKey X509.PrivKey) where toASN1 = asn1s fromASN1 = runParseASN1State parse instance ASN1Elem e => ProduceASN1Object e (Traditional X509.PrivKey) where asn1s (Traditional privKey) = snd $ traditionalPrivKeyASN1S privKey instance Monoid e => ParseASN1Object e (Traditional X509.PrivKey) where parse = rsa <|> dsa <|> ecdsa where rsa = Traditional . X509.PrivKeyRSA . unTraditional <$> parse dsa = Traditional . X509.PrivKeyDSA . DSA.toPrivateKey . unTraditional <$> parse ecdsa = Traditional . X509.PrivKeyEC . unTraditional <$> parse instance ASN1Elem e => ProduceASN1Object e (Modern X509.PrivKey) where asn1s (Modern attrs privKey) = modernPrivKeyASN1S attrs privKey instance Monoid e => ParseASN1Object e (Modern X509.PrivKey) where parse = rsa <|> dsa <|> ecdsa <|> x25519 <|> x448 <|> ed25519 <|> ed448 where rsa = fmap X509.PrivKeyRSA <$> parse dsa = fmap (X509.PrivKeyDSA . DSA.toPrivateKey) <$> parse ecdsa = fmap X509.PrivKeyEC <$> parse x25519 = fmap X509.PrivKeyX25519 <$> parse x448 = fmap X509.PrivKeyX448 <$> parse ed25519 = fmap X509.PrivKeyEd25519 <$> parse ed448 = fmap X509.PrivKeyEd448 <$> parse skipVersion :: Monoid e => ParseASN1 e () skipVersion = do IntVal v <- getNext when (v /= 0 && v /= 1) $ throwParseError ("PKCS8: parsed invalid version: " ++ show v) skipPublicKey :: Monoid e => ParseASN1 e () skipPublicKey = void (fmap Just parseTaggedPrimitive <|> return Nothing) where parseTaggedPrimitive = do { Other _ 1 bs <- getNext; return bs } parseAttrKeys :: Monoid e => ParseASN1 e ([Attribute], B.ByteString) parseAttrKeys = do OctetString bs <- getNext attrs <- parseAttributes (Container Context 0) skipPublicKey return (attrs, bs) -- RSA instance ASN1Object (FormattedKey RSA.PrivateKey) where toASN1 = asn1s fromASN1 = runParseASN1State parse instance ASN1Elem e => ProduceASN1Object e (Traditional RSA.PrivateKey) where asn1s (Traditional privKey) = asn1Container Sequence (v . n . e . d . p1 . p2 . pexp1 . pexp2 . pcoef) where pubKey = RSA.private_pub privKey v = gIntVal 0 n = gIntVal (RSA.public_n pubKey) e = gIntVal (RSA.public_e pubKey) d = gIntVal (RSA.private_d privKey) p1 = gIntVal (RSA.private_p privKey) p2 = gIntVal (RSA.private_q privKey) pexp1 = gIntVal (RSA.private_dP privKey) pexp2 = gIntVal (RSA.private_dQ privKey) pcoef = gIntVal (RSA.private_qinv privKey) instance Monoid e => ParseASN1Object e (Traditional RSA.PrivateKey) where parse = onNextContainer Sequence $ do IntVal 0 <- getNext IntVal n <- getNext IntVal e <- getNext IntVal d <- getNext IntVal p1 <- getNext IntVal p2 <- getNext IntVal pexp1 <- getNext IntVal pexp2 <- getNext IntVal pcoef <- getNext let pubKey = RSA.PublicKey { RSA.public_size = numBytes n , RSA.public_n = n , RSA.public_e = e } privKey = RSA.PrivateKey { RSA.private_pub = pubKey , RSA.private_d = d , RSA.private_p = p1 , RSA.private_q = p2 , RSA.private_dP = pexp1 , RSA.private_dQ = pexp2 , RSA.private_qinv = pcoef } return (Traditional privKey) instance ASN1Elem e => ProduceASN1Object e (Modern RSA.PrivateKey) where asn1s (Modern attrs privKey) = asn1Container Sequence (v . alg . bs . att) where v = gIntVal 0 alg = asn1Container Sequence (oid . gNull) oid = gOID [1,2,840,113549,1,1,1] bs = gOctetString (encodeASN1Object $ Traditional privKey) att = attributesASN1S (Container Context 0) attrs instance Monoid e => ParseASN1Object e (Modern RSA.PrivateKey) where parse = onNextContainer Sequence $ do skipVersion Null <- onNextContainer Sequence $ do OID [1,2,840,113549,1,1,1] <- getNext getNext (attrs, bs) <- parseAttrKeys let inner = decodeASN1' BER bs strError = Left . ("PKCS8: error decoding inner RSA: " ++) . show case either strError (runParseASN1 parseTraditional) inner of Left err -> throwParseError ("PKCS8: error parsing inner RSA: " ++ err) Right privKey -> return (Modern attrs privKey) -- DSA instance ASN1Object (FormattedKey DSA.KeyPair) where toASN1 = asn1s fromASN1 = runParseASN1State parse instance ASN1Elem e => ProduceASN1Object e (Traditional DSA.KeyPair) where asn1s (Traditional (DSA.KeyPair params pub priv)) = asn1Container Sequence (v . pqgASN1S params . pub' . priv') where v = gIntVal 0 pub' = gIntVal pub priv' = gIntVal priv instance Monoid e => ParseASN1Object e (Traditional DSA.KeyPair) where parse = onNextContainer Sequence $ do IntVal 0 <- getNext params <- parsePQG IntVal pub <- getNext IntVal priv <- getNext return (Traditional $ DSA.KeyPair params pub priv) instance ASN1Elem e => ProduceASN1Object e (Modern DSA.KeyPair) where asn1s (Modern attrs (DSA.KeyPair params _ priv)) = asn1Container Sequence (v . alg . bs . att) where v = gIntVal 0 alg = asn1Container Sequence (oid . pr) oid = gOID [1,2,840,10040,4,1] pr = asn1Container Sequence (pqgASN1S params) bs = gOctetString (encodeASN1S $ gIntVal priv) att = attributesASN1S (Container Context 0) attrs instance Monoid e => ParseASN1Object e (Modern DSA.KeyPair) where parse = onNextContainer Sequence $ do skipVersion params <- onNextContainer Sequence $ do OID [1,2,840,10040,4,1] <- getNext onNextContainer Sequence parsePQG (attrs, bs) <- parseAttrKeys case decodeASN1' BER bs of Right [IntVal priv] -> let pub = DSA.calculatePublic params priv in return (Modern attrs $ DSA.KeyPair params pub priv) Right _ -> throwParseError "PKCS8: invalid format when parsing inner DSA" Left e -> throwParseError ("PKCS8: error parsing inner DSA: " ++ show e) pqgASN1S :: ASN1Elem e => DSA.Params -> ASN1Stream e pqgASN1S params = p . q . g where p = gIntVal (DSA.params_p params) q = gIntVal (DSA.params_q params) g = gIntVal (DSA.params_g params) parsePQG :: Monoid e => ParseASN1 e DSA.Params parsePQG = do IntVal p <- getNext IntVal q <- getNext IntVal g <- getNext return DSA.Params { DSA.params_p = p , DSA.params_q = q , DSA.params_g = g } dsaPrivToPair :: DSA.PrivateKey -> DSA.KeyPair dsaPrivToPair k = DSA.KeyPair params pub x where pub = DSA.calculatePublic params x params = DSA.private_params k x = DSA.private_x k -- ECDSA instance ASN1Object (FormattedKey X509.PrivKeyEC) where toASN1 = asn1s fromASN1 = runParseASN1State parse instance ASN1Elem e => ProduceASN1Object e (Traditional X509.PrivKeyEC) where asn1s = innerEcdsaASN1S True . unTraditional instance Monoid e => ParseASN1Object e (Traditional X509.PrivKeyEC) where parse = Traditional <$> parseInnerEcdsa Nothing instance ASN1Elem e => ProduceASN1Object e (Modern X509.PrivKeyEC) where asn1s (Modern attrs privKey) = asn1Container Sequence (v . f . bs . att) where v = gIntVal 0 f = asn1Container Sequence (oid . curveFnASN1S privKey) oid = gOID [1,2,840,10045,2,1] bs = gOctetString (encodeASN1S inner) inner = innerEcdsaASN1S False privKey att = attributesASN1S (Container Context 0) attrs instance Monoid e => ParseASN1Object e (Modern X509.PrivKeyEC) where parse = onNextContainer Sequence $ do skipVersion f <- onNextContainer Sequence $ do OID [1,2,840,10045,2,1] <- getNext parseCurveFn (attrs, bs) <- parseAttrKeys let inner = decodeASN1' BER bs strError = Left . ("PKCS8: error decoding inner EC: " ++) . show case either strError (runParseASN1 $ parseInnerEcdsa $ Just f) inner of Left err -> throwParseError ("PKCS8: error parsing inner EC: " ++ err) Right privKey -> return (Modern attrs privKey) innerEcdsaASN1S :: ASN1Elem e => Bool -> X509.PrivKeyEC -> ASN1Stream e innerEcdsaASN1S addC k | addC = asn1Container Sequence (v . ds . c0 . c1) | otherwise = asn1Container Sequence (v . ds . c1) where curve = fromMaybe (error "PKCS8: invalid EC parameters") (ecPrivKeyCurve k) bytes = curveOrderBytes curve v = gIntVal 1 ds = gOctetString (i2ospOf_ bytes (X509.privkeyEC_priv k)) c0 = asn1Container (Container Context 0) (curveFnASN1S k) c1 = asn1Container (Container Context 1) pub pub = gBitString (toBitArray sp 0) X509.SerializedPoint sp = getSerializedPoint curve (X509.privkeyEC_priv k) parseInnerEcdsa :: Monoid e => Maybe (ECDSA.PrivateNumber -> X509.PrivKeyEC) -> ParseASN1 e X509.PrivKeyEC parseInnerEcdsa fn = onNextContainer Sequence $ do IntVal 1 <- getNext OctetString ds <- getNext let d = os2ip ds m <- onNextContainerMaybe (Container Context 0) parseCurveFn _ <- onNextContainerMaybe (Container Context 1) parsePK case fn <|> m of Nothing -> throwParseError "PKCS8: no curve found in EC private key" Just getKey -> return (getKey d) where parsePK = do { BitString bs <- getNext; return bs } curveFnASN1S :: ASN1Elem e => X509.PrivKeyEC -> ASN1Stream e curveFnASN1S X509.PrivKeyEC_Named{..} = gOID (curveNameOID privkeyEC_name) curveFnASN1S X509.PrivKeyEC_Prime{..} = asn1Container Sequence (v . prime . abSeed . gen . o . c) where X509.SerializedPoint generator = privkeyEC_generator bytes = numBytes privkeyEC_prime v = gIntVal 1 prime = asn1Container Sequence (oid . p) oid = gOID [1,2,840,10045,1,1] p = gIntVal privkeyEC_prime abSeed = asn1Container Sequence (a . b . seed) a = gOctetString (i2ospOf_ bytes privkeyEC_a) b = gOctetString (i2ospOf_ bytes privkeyEC_b) seed = if privkeyEC_seed > 0 then gBitString (toBitArray (i2osp privkeyEC_seed) 0) else id gen = gOctetString generator o = gIntVal privkeyEC_order c = gIntVal privkeyEC_cofactor parseCurveFn :: Monoid e => ParseASN1 e (ECDSA.PrivateNumber -> X509.PrivKeyEC) parseCurveFn = parseNamedCurve <|> parsePrimeCurve where parseNamedCurve = do OID oid <- getNext case lookupCurveNameByOID oid of Just name -> return $ \d -> X509.PrivKeyEC_Named { X509.privkeyEC_name = name , X509.privkeyEC_priv = d } Nothing -> throwParseError ("PKCS8: unknown EC curve with OID " ++ show oid) parsePrimeCurve = onNextContainer Sequence $ do IntVal 1 <- getNext prime <- onNextContainer Sequence $ do OID [1,2,840,10045,1,1] <- getNext IntVal prime <- getNext return prime (a, b, seed) <- onNextContainer Sequence $ do OctetString a <- getNext OctetString b <- getNext seed <- parseOptionalSeed return (a, b, seed) OctetString generator <- getNext IntVal order <- getNext IntVal cofactor <- getNext return $ \d -> X509.PrivKeyEC_Prime { X509.privkeyEC_priv = d , X509.privkeyEC_a = os2ip a , X509.privkeyEC_b = os2ip b , X509.privkeyEC_prime = prime , X509.privkeyEC_generator = X509.SerializedPoint generator , X509.privkeyEC_order = order , X509.privkeyEC_cofactor = cofactor , X509.privkeyEC_seed = seed } parseOptionalSeed = do seedAvail <- hasNext if seedAvail then do BitString seed <- getNext return (os2ip $ bitArrayGetData seed) else return 0 -- X25519, X448, Ed25519, Ed448 instance ASN1Elem e => ProduceASN1Object e (Modern X25519.SecretKey) where asn1s (Modern attrs privKey) = asn1Container Sequence (v . alg . bs . att) where v = gIntVal 0 alg = asn1Container Sequence (gOID [1,3,101,110]) bs = innerEddsaASN1S privKey att = attributesASN1S (Container Context 0) attrs instance Monoid e => ParseASN1Object e (Modern X25519.SecretKey) where parse = onNextContainer Sequence $ do skipVersion onNextContainer Sequence $ do { OID [1,3,101,110] <- getNext; return () } (attrs, bs) <- parseAttrKeys Modern attrs <$> parseInnerEddsa "X25519" X25519.secretKey bs instance ASN1Elem e => ProduceASN1Object e (Modern X448.SecretKey) where asn1s (Modern attrs privKey) = asn1Container Sequence (v . alg . bs . att) where v = gIntVal 0 alg = asn1Container Sequence (gOID [1,3,101,111]) bs = innerEddsaASN1S privKey att = attributesASN1S (Container Context 0) attrs instance Monoid e => ParseASN1Object e (Modern X448.SecretKey) where parse = onNextContainer Sequence $ do skipVersion onNextContainer Sequence $ do { OID [1,3,101,111] <- getNext; return () } (attrs, bs) <- parseAttrKeys Modern attrs <$> parseInnerEddsa "X448" X448.secretKey bs instance ASN1Elem e => ProduceASN1Object e (Modern Ed25519.SecretKey) where asn1s (Modern attrs privKey) = asn1Container Sequence (v . alg . bs . att) where v = gIntVal 0 alg = asn1Container Sequence (gOID [1,3,101,112]) bs = innerEddsaASN1S privKey att = attributesASN1S (Container Context 0) attrs instance Monoid e => ParseASN1Object e (Modern Ed25519.SecretKey) where parse = onNextContainer Sequence $ do skipVersion onNextContainer Sequence $ do { OID [1,3,101,112] <- getNext; return () } (attrs, bs) <- parseAttrKeys Modern attrs <$> parseInnerEddsa "Ed25519" Ed25519.secretKey bs instance ASN1Elem e => ProduceASN1Object e (Modern Ed448.SecretKey) where asn1s (Modern attrs privKey) = asn1Container Sequence (v . alg . bs . att) where v = gIntVal 0 alg = asn1Container Sequence (gOID [1,3,101,113]) bs = innerEddsaASN1S privKey att = attributesASN1S (Container Context 0) attrs instance Monoid e => ParseASN1Object e (Modern Ed448.SecretKey) where parse = onNextContainer Sequence $ do skipVersion onNextContainer Sequence $ do { OID [1,3,101,113] <- getNext; return () } (attrs, bs) <- parseAttrKeys Modern attrs <$> parseInnerEddsa "Ed448" Ed448.secretKey bs innerEddsaASN1S :: (ASN1Elem e, ByteArrayAccess key) => key -> ASN1Stream e innerEddsaASN1S key = gOctetString (encodeASN1S inner) where inner = gOctetString (convert key) parseInnerEddsa :: Monoid e => String -> (B.ByteString -> CryptoFailable key) -> B.ByteString -> ParseASN1 e key parseInnerEddsa name buildKey input = case either strError (runParseASN1 parser) (decodeASN1' BER input) of Left err -> throwParseError ("PKCS8: error parsing inner " ++ name ++ ": " ++ err) Right privKey -> return privKey where innerMsg = "PKCS8: error decoding inner " ++ name ++ ": " strError = Left . (innerMsg ++) . show parser = do OctetString bs <- getNext case buildKey bs of CryptoPassed privKey -> return privKey CryptoFailed _ -> throwParseError ("PKCS8: parsed invalid " ++ name ++ " secret key") cryptostore-0.3.1.0/src/Crypto/Store/PKCS8/0000755000000000000000000000000007346545000016432 5ustar0000000000000000cryptostore-0.3.1.0/src/Crypto/Store/PKCS8/EC.hs0000644000000000000000000000555007346545000017262 0ustar0000000000000000-- | -- Module : Crypto.Store.PKCS8.EC -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- Additional EC utilities. module Crypto.Store.PKCS8.EC ( numBytes , curveSizeBytes , curveOrderBytes , curveNameOID , getSerializedPoint , module Data.X509.EC ) where import Data.ASN1.OID import qualified Data.ByteString as B import Data.Maybe (fromMaybe) import Data.X509 import Data.X509.EC import Crypto.Number.Basic (numBits, numBytes) import Crypto.Number.Serialize (i2ospOf_) import Crypto.PubKey.ECC.Prim import Crypto.PubKey.ECC.Types import Crypto.Store.CMS.Util -- | Number of bytes necessary to serialize n bits. bitsToBytes :: Int -> Int bitsToBytes n = (n + 7) `div` 8 -- | Number of bytes to serialize a field element. curveSizeBytes :: Curve -> Int curveSizeBytes = bitsToBytes . curveSizeBits -- | Number of bytes to serialize a scalar. curveOrderBytes :: Curve -> Int curveOrderBytes = bitsToBytes . numBits . ecc_n . common_curve -- | Transform a private scalar to a point in uncompressed format. getSerializedPoint :: Curve -> PrivateNumber -> SerializedPoint getSerializedPoint curve d = SerializedPoint (serializePoint pt) where pt = pointBaseMul curve d bs = i2ospOf_ (curveSizeBytes curve) serializePoint PointO = B.singleton 0 serializePoint (Point x y) = B.cons 4 (B.append (bs x) (bs y)) -- | Return the OID associated to a curve name. curveNameOID :: CurveName -> OID curveNameOID name = fromMaybe (error $ "PKCS8: OID unknown for EC curve " ++ show name) (lookupOID curvesOIDTable name) curvesOIDTable :: OIDTable CurveName curvesOIDTable = [ (SEC_p112r1, [1,3,132,0,6]) , (SEC_p112r2, [1,3,132,0,7]) , (SEC_p128r1, [1,3,132,0,28]) , (SEC_p128r2, [1,3,132,0,29]) , (SEC_p160k1, [1,3,132,0,9]) , (SEC_p160r1, [1,3,132,0,8]) , (SEC_p160r2, [1,3,132,0,30]) , (SEC_p192k1, [1,3,132,0,31]) , (SEC_p192r1, [1,2,840,10045,3,1,1]) , (SEC_p224k1, [1,3,132,0,32]) , (SEC_p224r1, [1,3,132,0,33]) , (SEC_p256k1, [1,3,132,0,10]) , (SEC_p256r1, [1,2,840,10045,3,1,7]) , (SEC_p384r1, [1,3,132,0,34]) , (SEC_p521r1, [1,3,132,0,35]) , (SEC_t113r1, [1,3,132,0,4]) , (SEC_t113r2, [1,3,132,0,5]) , (SEC_t131r1, [1,3,132,0,22]) , (SEC_t131r2, [1,3,132,0,23]) , (SEC_t163k1, [1,3,132,0,1]) , (SEC_t163r1, [1,3,132,0,2]) , (SEC_t163r2, [1,3,132,0,15]) , (SEC_t193r1, [1,3,132,0,24]) , (SEC_t193r2, [1,3,132,0,25]) , (SEC_t233k1, [1,3,132,0,26]) , (SEC_t233r1, [1,3,132,0,27]) , (SEC_t239k1, [1,3,132,0,3]) , (SEC_t283k1, [1,3,132,0,16]) , (SEC_t283r1, [1,3,132,0,17]) , (SEC_t409k1, [1,3,132,0,36]) , (SEC_t409r1, [1,3,132,0,37]) , (SEC_t571k1, [1,3,132,0,38]) , (SEC_t571r1, [1,3,132,0,39]) ] cryptostore-0.3.1.0/src/Crypto/Store/Util.hs0000644000000000000000000000371407346545000017060 0ustar0000000000000000-- | -- Module : Crypto.Store.Util -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- {-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE MagicHash #-} module Crypto.Store.Util ( (&&!) , reverseBytes , constAllEq , mapLeft , mapAsWord64LE ) where import Data.Bits import Data.ByteArray (ByteArray, ByteArrayAccess) import qualified Data.ByteArray as B import Data.List import Data.Memory.Endian import Data.Word import Foreign.Ptr (plusPtr) import Foreign.Storable import GHC.Exts -- | This is a strict version of &&. (&&!) :: Bool -> Bool -> Bool (&&!) x y = isTrue# (andI# (getTag# x) (getTag# y)) where getTag# !z = dataToTag# z infixr 3 &&! -- | Reverse a bytearray. reverseBytes :: ByteArray ba => ba -> ba #if MIN_VERSION_memory(0,14,18) reverseBytes = B.reverse #else reverseBytes = B.pack . reverse . B.unpack #endif -- | Test if all bytes in a bytearray are equal to the value specified. Runs in -- constant time. constAllEq :: ByteArrayAccess ba => Word8 -> ba -> Bool constAllEq b = (== 0) . foldl' fn 0 . B.unpack where fn acc x = acc .|. xor b x -- | Map over the left value. mapLeft :: (a -> b) -> Either a c -> Either b c mapLeft f (Left a) = Left (f a) mapLeft _ (Right c) = Right c -- | Same as 'Data.ByteArray.Mapping.mapAsWord64' but with little-endian words. mapAsWord64LE :: ByteArray bs => (Word64 -> Word64) -> bs -> bs mapAsWord64LE f bs = B.allocAndFreeze len $ \dst -> B.withByteArray bs $ \src -> loop (len `div` 8) dst src where len = B.length bs loop :: Int -> Ptr (LE Word64) -> Ptr (LE Word64) -> IO () loop 0 _ _ = return () loop i d s = do w <- peek s let r = f (fromLE w) poke d (toLE r) loop (i - 1) (d `plusPtr` 8) (s `plusPtr` 8) cryptostore-0.3.1.0/src/Crypto/Store/X509.hs0000644000000000000000000001336107346545000016607 0ustar0000000000000000-- | -- Module : Crypto.Store.X509 -- License : BSD-style -- Maintainer : Olivier Chéron -- Stability : experimental -- Portability : unknown -- -- Public keys, certificates and CRLs. -- -- Presents an API similar to "Data.X509.Memory" and "Data.X509.File" but -- provides support for public-key files and allows to write objects. -- -- Functions related to private keys are available from "Crypto.Store.PKCS8". {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} module Crypto.Store.X509 ( SignedObject() -- * Public keys , readPubKeyFile , readPubKeyFileFromMemory , pemToPubKey , writePubKeyFile , writePubKeyFileToMemory , pubKeyToPEM -- * Signed objects , readSignedObject , readSignedObjectFromMemory , writeSignedObject , writeSignedObjectToMemory -- * Reading and writing PEM files , readPEMs , writePEMs ) where import Data.ASN1.Types import Data.ASN1.BinaryEncoding import Data.ASN1.Encoding import Data.Maybe import Data.Proxy import qualified Data.X509 as X509 import qualified Data.ByteString as B import Crypto.Number.Basic (numBytes) import qualified Crypto.PubKey.RSA as RSA import Crypto.Store.ASN1.Generate import Crypto.Store.ASN1.Parse import Crypto.Store.CMS.Util import Crypto.Store.PEM -- | Class of signed objects convertible to PEM. class (ASN1Object a, Eq a, Show a) => SignedObject a where signedObjectName :: proxy a -> String otherObjectNames :: proxy a -> [String] instance SignedObject X509.Certificate where signedObjectName _ = "CERTIFICATE" otherObjectNames _ = ["X509 CERTIFICATE"] instance SignedObject X509.CRL where signedObjectName _ = "X509 CRL" otherObjectNames _ = [] validObjectName :: SignedObject a => proxy a -> String -> Bool validObjectName prx name = name == signedObjectName prx || name `elem` otherObjectNames prx -- Reading from PEM format -- | Read public keys from a PEM file. readPubKeyFile :: FilePath -> IO [X509.PubKey] readPubKeyFile path = accumulate <$> readPEMs path -- | Read public keys from a bytearray in PEM format. readPubKeyFileFromMemory :: B.ByteString -> [X509.PubKey] readPubKeyFileFromMemory = either (const []) accumulate . pemParseBS accumulate :: [PEM] -> [X509.PubKey] accumulate = catMaybes . foldr (flip pemToPubKey) [] -- | Read a public key from a 'PEM' element and add it to the accumulator list. pemToPubKey :: [Maybe X509.PubKey] -> PEM -> [Maybe X509.PubKey] pemToPubKey acc pem = case decodeASN1' BER (pemContent pem) of Left _ -> acc Right asn1 -> run (getParser $ pemName pem) asn1 : acc where run p asn1 = case p asn1 of Right (pubKey, []) -> Just pubKey _ -> Nothing getParser "PUBLIC KEY" = fromASN1 getParser "RSA PUBLIC KEY" = runParseASN1State rsapkParser getParser _ = const (Left undefined) rsapkParser = (\(RSAPublicKey pub) -> X509.PubKeyRSA pub) <$> parse -- | Read signed objects from a PEM file (only one type at a time). readSignedObject :: SignedObject a => FilePath -> IO [X509.SignedExact a] readSignedObject path = accumulate' <$> readPEMs path -- | Read signed objects from a bytearray in PEM format (only one type at a -- time). readSignedObjectFromMemory :: SignedObject a => B.ByteString -> [X509.SignedExact a] readSignedObjectFromMemory = either (const []) accumulate' . pemParseBS accumulate' :: forall a. SignedObject a => [PEM] -> [X509.SignedExact a] accumulate' = foldr pemToSigned [] where prx = Proxy :: Proxy a pemToSigned pem acc | validObjectName prx (pemName pem) = case X509.decodeSignedObject $ pemContent pem of Left _ -> acc Right obj -> obj : acc | otherwise = acc -- Writing to PEM format -- | Write public keys to a PEM file. writePubKeyFile :: FilePath -> [X509.PubKey] -> IO () writePubKeyFile path = writePEMs path . map pubKeyToPEM -- | Write public keys to a bytearray in PEM format. writePubKeyFileToMemory :: [X509.PubKey] -> B.ByteString writePubKeyFileToMemory = pemsWriteBS . map pubKeyToPEM -- | Generate a PEM for a public key. pubKeyToPEM :: X509.PubKey -> PEM pubKeyToPEM pubKey = mkPEM "PUBLIC KEY" (encodeASN1S $ gMany asn1) where asn1 = toASN1 pubKey [] -- | Write signed objects to a PEM file. writeSignedObject :: SignedObject a => FilePath -> [X509.SignedExact a] -> IO () writeSignedObject path = writePEMs path . map signedToPEM -- | Write signed objects to a bytearray in PEM format. writeSignedObjectToMemory :: SignedObject a => [X509.SignedExact a] -> B.ByteString writeSignedObjectToMemory = pemsWriteBS . map signedToPEM signedToPEM :: forall a. SignedObject a => X509.SignedExact a -> PEM signedToPEM obj = mkPEM (signedObjectName prx) (X509.encodeSignedObject obj) where prx = Proxy :: Proxy a mkPEM :: String -> B.ByteString -> PEM mkPEM name bs = PEM { pemName = name, pemHeader = [], pemContent = bs} -- RSA public keys newtype RSAPublicKey = RSAPublicKey RSA.PublicKey instance ASN1Elem e => ProduceASN1Object e RSAPublicKey where asn1s (RSAPublicKey pub) = asn1Container Sequence (n . e) where n = gIntVal (RSA.public_n pub) e = gIntVal (RSA.public_e pub) instance Monoid e => ParseASN1Object e RSAPublicKey where parse = onNextContainer Sequence $ do IntVal modulus <- getNext IntVal pubexp <- getNext let pub = RSA.PublicKey { RSA.public_size = numBytes modulus , RSA.public_n = modulus , RSA.public_e = pubexp } return (RSAPublicKey pub) cryptostore-0.3.1.0/tests/CMS/0000755000000000000000000000000007346545000014223 5ustar0000000000000000cryptostore-0.3.1.0/tests/CMS/Instances.hs0000644000000000000000000004324307346545000016514 0ustar0000000000000000{-# LANGUAGE OverloadedStrings #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- | Orphan instances. module CMS.Instances ( arbitraryPassword , arbitraryAttributes , arbitraryIntegrityDigest , arbitrarySigVer , arbitraryEnvDev ) where import Data.ASN1.Types import qualified Data.ByteArray as B import Data.ByteString (ByteString) import Data.X509 import GHC.TypeLits import Test.Tasty.QuickCheck import Crypto.Cipher.Types import Crypto.Store.CMS import Crypto.Store.Error import X509.Instances arbitrarySmall :: Gen ByteString arbitrarySmall = resize 10 (B.pack <$> arbitrary) arbitraryPassword :: Gen ByteString arbitraryPassword = resize 16 (B.pack <$> asciiChar) where asciiChar = listOf $ choose (0x20,0x7f) instance Arbitrary ContentInfo where arbitrary = sized $ \n -> if n == 0 then DataCI <$> arbitraryMessage else oneof [ DataCI <$> arbitraryMessage , arbitraryMode <*> arbitrarySignedData , arbitraryMode <*> arbitraryEnvelopedData , arbitraryMode <*> arbitraryDigestedData , arbitraryMode <*> arbitraryEncryptedData , arbitraryMode <*> arbitraryAuthenticatedData , arbitraryMode <*> arbitraryAuthEnvelopedData ] where arbitraryMessage :: Gen ByteString arbitraryMessage = resize 2048 (B.pack <$> arbitrary) arbitraryMode :: Encapsulates struct => Gen (struct ByteString -> ContentInfo) arbitraryMode = elements [ toAttachedCI, snd . toDetachedCI ] arbitrarySignedData :: Gen (SignedData EncapsulatedContent) arbitrarySignedData = do alg <- arbitrary (sigFns, _) <- arbitrarySigVer alg inner <- scale (subtract $ length sigFns) arbitrary signData sigFns inner >>= failIfError arbitraryEnvelopedData :: Gen (EnvelopedData EncryptedContent) arbitraryEnvelopedData = do oinfo <- arbitrary (alg, key, attrs) <- getCommon (envFns, _) <- arbitraryEnvDev key inner <- scale (subtract $ length envFns) arbitrary envelopData oinfo key alg envFns attrs inner >>= failIfError arbitraryDigestedData :: Gen (DigestedData EncapsulatedContent) arbitraryDigestedData = do inner <- scale pred arbitrary dt <- arbitrary return $ digestData dt inner arbitraryEncryptedData :: Gen (EncryptedData EncryptedContent) arbitraryEncryptedData = do (alg, key, attrs) <- getCommon inner <- scale pred arbitrary failIfError $ encryptData key alg attrs inner arbitraryAuthenticatedData :: Gen (AuthenticatedData EncapsulatedContent) arbitraryAuthenticatedData = do (oinfo, alg, key, envFns, aAttrs, uAttrs) <- getCommonAuth dig <- arbitrary inner <- scale (subtract $ length envFns) arbitrary generateAuthenticatedData oinfo key alg dig envFns aAttrs uAttrs inner >>= failIfError arbitraryAuthEnvelopedData :: Gen (AuthEnvelopedData EncryptedContent) arbitraryAuthEnvelopedData = do (oinfo, alg, key, envFns, aAttrs, uAttrs) <- getCommonAuth inner <- scale (subtract $ length envFns) arbitrary authEnvelopData oinfo key alg envFns aAttrs uAttrs inner >>= failIfError getCommonAuth :: (HasKeySize params, Arbitrary params) => Gen ( OriginatorInfo, params, ContentEncryptionKey , [ProducerOfRI Gen], [Attribute], [Attribute] ) getCommonAuth = do oinfo <- arbitrary (alg, key, uAttrs) <- getCommon aAttrs <- arbitraryAttributes (envFns, _) <- arbitraryEnvDev key return (oinfo, alg, key, envFns, aAttrs, uAttrs) getCommon :: (HasKeySize params, Arbitrary params, B.ByteArray key) => Gen (params, key, [Attribute]) getCommon = do alg <- arbitrary key <- generateKey alg attrs <- arbitraryAttributes return (alg, key, attrs) failIfError :: Either StoreError a -> Gen a failIfError = either (error . show) return instance Arbitrary Attribute where arbitrary = do oid <- arbitraryOID vals <- resize 3 $ listOf1 (OctetString <$> arbitrarySmall) return Attribute { attrType = oid, attrValues = vals } arbitraryAttributes :: Gen [Attribute] arbitraryAttributes = resize 3 arbitrary arbitraryNat :: Gen SomeNat arbitraryNat = unwrap <$> arbitrary where unwrap (Positive i) = let Just n = someNatVal (127 + i) in n instance Arbitrary DigestAlgorithm where arbitrary = oneof [ pure $ DigestAlgorithm MD2 , pure $ DigestAlgorithm MD4 , pure $ DigestAlgorithm MD5 , pure $ DigestAlgorithm SHA1 , pure $ DigestAlgorithm SHA224 , pure $ DigestAlgorithm SHA256 , pure $ DigestAlgorithm SHA384 , pure $ DigestAlgorithm SHA512 , pure $ DigestAlgorithm SHAKE128_256 , pure $ DigestAlgorithm SHAKE256_512 , (\(SomeNat p) -> DigestAlgorithm (SHAKE128 p)) <$> arbitraryNat , (\(SomeNat p) -> DigestAlgorithm (SHAKE256 p)) <$> arbitraryNat ] arbitraryIntegrityDigest :: Gen DigestAlgorithm arbitraryIntegrityDigest = elements [ DigestAlgorithm MD5 , DigestAlgorithm SHA1 , DigestAlgorithm SHA224 , DigestAlgorithm SHA256 , DigestAlgorithm SHA384 , DigestAlgorithm SHA512 ] instance Arbitrary MACAlgorithm where arbitrary = oneof [ (\(DigestAlgorithm alg) -> HMAC alg) <$> arbitraryIntegrityDigest , (\(SomeNat p) -> KMAC_SHAKE128 p) <$> arbitraryNat <*> arbitraryCtx , (\(SomeNat p) -> KMAC_SHAKE256 p) <$> arbitraryNat <*> arbitraryCtx ] where arbitraryCtx = elements [ B.empty , "ctx" , "custom string" ] instance Arbitrary OAEPParams where arbitrary = do alg <- arbitrary mga <- MGF1 <$> arbitrary return OAEPParams { oaepHashAlgorithm = alg , oaepMaskGenAlgorithm = mga } instance Arbitrary PSSParams where arbitrary = do alg <- arbitrary mga <- MGF1 <$> arbitrary len <- choose (1, 30) return PSSParams { pssHashAlgorithm = alg , pssMaskGenAlgorithm = mga , pssSaltLength = len } instance Arbitrary SignatureAlg where arbitrary = oneof [ pure RSAAnyHash , pure $ RSA (DigestAlgorithm MD2) , pure $ RSA (DigestAlgorithm MD5) , pure $ RSA (DigestAlgorithm SHA1) , pure $ RSA (DigestAlgorithm SHA224) , pure $ RSA (DigestAlgorithm SHA256) , pure $ RSA (DigestAlgorithm SHA384) , pure $ RSA (DigestAlgorithm SHA512) , RSAPSS <$> arbitrary , pure $ DSA (DigestAlgorithm SHA1) , pure $ DSA (DigestAlgorithm SHA224) , pure $ DSA (DigestAlgorithm SHA256) , pure $ ECDSA (DigestAlgorithm SHA1) , pure $ ECDSA (DigestAlgorithm SHA224) , pure $ ECDSA (DigestAlgorithm SHA256) , pure $ ECDSA (DigestAlgorithm SHA384) , pure $ ECDSA (DigestAlgorithm SHA512) , pure Ed25519 , pure Ed448 ] arbitraryKeyPair :: SignatureAlg -> Gen (PubKey, PrivKey) arbitraryKeyPair RSAAnyHash = do (pub, priv) <- arbitraryRSA return (PubKeyRSA pub, PrivKeyRSA priv) arbitraryKeyPair (RSA _) = do (pub, priv) <- arbitraryRSA return (PubKeyRSA pub, PrivKeyRSA priv) arbitraryKeyPair (RSAPSS _) = do (pub, priv) <- arbitraryRSA return (PubKeyRSA pub, PrivKeyRSA priv) arbitraryKeyPair (DSA _) = do (pub, priv) <- arbitraryDSA return (PubKeyDSA pub, PrivKeyDSA priv) arbitraryKeyPair (ECDSA _) = do (pub, priv) <- arbitraryNamedEC return (PubKeyEC pub, PrivKeyEC priv) arbitraryKeyPair Ed25519 = do (pub, priv) <- arbitraryEd25519 return (PubKeyEd25519 pub, PrivKeyEd25519 priv) arbitraryKeyPair Ed448 = do (pub, priv) <- arbitraryEd448 return (PubKeyEd448 pub, PrivKeyEd448 priv) arbitrarySigVer :: SignatureAlg -> Gen ([ProducerOfSI Gen], ConsumerOfSI Gen) arbitrarySigVer alg = sized $ \n -> do (sigFn, verFn) <- onePair otherPairs <- resize (min (pred n) 3) $ listOf onePair sigFns <- shuffle (sigFn : map fst otherPairs) return (sigFns, verFn) where onePair = do (pub, priv) <- arbitraryKeyPair alg chain <- arbitraryCertificateChain pub sAttrs <- oneof [ pure Nothing, Just <$> arbitraryAttributes ] uAttrs <- arbitraryAttributes return (certSigner alg priv chain sAttrs uAttrs, withPublicKey pub) instance Arbitrary PBKDF2_PRF where arbitrary = elements [ PBKDF2_SHA1 , PBKDF2_SHA256 , PBKDF2_SHA512 ] instance Arbitrary ContentEncryptionAlg where arbitrary = elements [ CBC DES , CBC DES_EDE3 , CBC AES128 , CBC AES192 , CBC AES256 , CBC CAST5 , CBC Camellia128 , CBC_RC2 , ECB DES , ECB AES128 , ECB AES192 , ECB AES256 , ECB Camellia128 , CFB DES , CFB AES128 , CFB AES192 , CFB AES256 , CFB Camellia128 , CTR Camellia128 ] instance Arbitrary ContentEncryptionParams where arbitrary = arbitrary >>= gen where gen CBC_RC2 = choose (24, 512) >>= generateRC2EncryptionParams gen alg = generateEncryptionParams alg instance Arbitrary AuthContentEncryptionAlg where arbitrary = elements [ AUTH_ENC_128 , AUTH_ENC_256 , CHACHA20_POLY1305 , CCM AES128 , CCM AES192 , CCM AES256 , GCM AES128 , GCM AES192 , GCM AES256 ] instance Arbitrary AuthContentEncryptionParams where arbitrary = do alg <- arbitrary case alg of AUTH_ENC_128 -> arb3 generateAuthEnc128Params AUTH_ENC_256 -> arb3 generateAuthEnc256Params CHACHA20_POLY1305 -> generateChaChaPoly1305Params CCM c -> do m <- arbitraryM l <- arbitraryL generateCCMParams c m l GCM c -> choose (12,16) >>= generateGCMParams c where arb3 fn = do a <- arbitrary; b <- arbitrary; c <- arbitrary fn a b c arbitraryM :: Gen CCM_M arbitraryM = elements [ CCM_M4 , CCM_M6 , CCM_M8 , CCM_M10 , CCM_M12 , CCM_M14 , CCM_M16 ] arbitraryL :: Gen CCM_L arbitraryL = elements [ CCM_L2, CCM_L3, CCM_L4 ] instance Arbitrary KeyDerivationFunc where arbitrary = do salt <- generateSalt 8 oneof [ pbkdf2 salt , scrypt salt ] where pbkdf2 salt = do iters <- choose (1,512) pf <- arbitrary return PBKDF2 { pbkdf2Salt = salt , pbkdf2IterationCount = iters , pbkdf2KeyLength = Nothing , pbkdf2Prf = pf } scrypt salt = do (n, r, p) <- elements [ (16, 1, 1) , (1024, 8, 16) ] return Scrypt { scryptSalt = salt , scryptN = n , scryptR = r , scryptP = p , scryptKeyLength = Nothing } instance Arbitrary KeyTransportParams where arbitrary = oneof [ pure RSAES , RSAESOAEP <$> arbitrary ] instance Arbitrary KeyEncryptionParams where arbitrary = oneof [ PWRIKEK <$> arbitrary , return AES128_WRAP , return AES192_WRAP , return AES256_WRAP , return AES128_WRAP_PAD , return AES192_WRAP_PAD , return AES256_WRAP_PAD , return DES_EDE3_WRAP , RC2_WRAP <$> choose (1, 1024) ] instance Arbitrary OtherKeyAttribute where arbitrary = do oid <- arbitraryOID vals <- resize 3 $ listOf1 (OctetString <$> arbitrarySmall) return OtherKeyAttribute { keyAttrId = oid, keyAttr = vals } instance Arbitrary KeyIdentifier where arbitrary = do kid <- arbitrarySmall KeyIdentifier kid Nothing <$> arbitrary arbitraryAgreeParams :: Bool -> KeyEncryptionParams -> Gen KeyAgreementParams arbitraryAgreeParams allowCofactorDH alg | allowCofactorDH = oneof [ flip StdDH alg <$> elements stdKDFs , flip CofactorDH alg <$> elements cofactorKDFs ] | otherwise = flip StdDH alg <$> elements stdKDFs where cofactorKDFs = [ KA_X963_KDF SHA1 , KA_X963_KDF SHA224 , KA_X963_KDF SHA256 , KA_X963_KDF SHA384 , KA_X963_KDF SHA512 ] stdKDFs = cofactorKDFs ++ [ KA_HKDF SHA256 , KA_HKDF SHA384 , KA_HKDF SHA512 ] arbitraryEnvDev :: ContentEncryptionKey -> Gen ([ProducerOfRI Gen], ConsumerOfRI Gen) arbitraryEnvDev cek = sized $ \n -> do (envFn, devFn) <- onePair otherPairs <- resize (min (pred n) 3) $ listOf onePair envFns <- shuffle (envFn : map fst otherPairs) return (envFns, devFn) where len = B.length cek onePair = oneof [ arbitraryKT, arbitraryKA, arbitraryKEK, arbitraryPW ] arbitraryKT = do (pub, priv) <- arbitraryLargeRSA cert <- arbitrarySignedCertificate (PubKeyRSA pub) ktp <- arbitrary let envFn = forKeyTransRecipient cert ktp devFn = withRecipientKeyTrans (PrivKeyRSA priv) return (envFn, devFn) arbitraryKA = do (cert, priv) <- arbitraryDHParams let allowCofactorDH = case priv of PrivKeyEC _ -> True _ -> False kap <- arbitraryAlg >>= arbitraryAgreeParams allowCofactorDH let envFn = forKeyAgreeRecipient cert kap devFn = withRecipientKeyAgree priv cert return (envFn, devFn) arbitraryKEK = do kid <- arbitrary es <- arbitraryAlg key <- generateKey es return (forKeyRecipient key kid es, withRecipientKey key) arbitraryPW = do pwd <- arbitraryPassword kdf <- arbitrary cea <- arbitrary `suchThat` notModeCTR let es = PWRIKEK cea return (forPasswordRecipient pwd kdf es, withRecipientPassword pwd) arbitraryAlg | len == 24 = oneof [ return AES128_WRAP , return AES192_WRAP , return AES256_WRAP , return AES128_WRAP_PAD , return AES192_WRAP_PAD , return AES256_WRAP_PAD , return DES_EDE3_WRAP , RC2_WRAP <$> choose (1, 1024) ] | mod len 8 == 0 = oneof [ return AES128_WRAP , return AES192_WRAP , return AES256_WRAP , return AES128_WRAP_PAD , return AES192_WRAP_PAD , return AES256_WRAP_PAD , RC2_WRAP <$> choose (1, 1024) ] | otherwise = oneof [ return AES128_WRAP_PAD , return AES192_WRAP_PAD , return AES256_WRAP_PAD , RC2_WRAP <$> choose (1, 1024) ] arbitraryDHParams = oneof [ arbitraryCredNamedEC , arbitraryCredX25519 , arbitraryCredX448 ] arbitraryCredNamedEC = do (pub, priv) <- arbitraryNamedEC cert <- arbitrarySignedCertificate (PubKeyEC pub) return (cert, PrivKeyEC priv) arbitraryCredX25519 = do (pub, priv) <- arbitraryX25519 cert <- arbitrarySignedCertificate (PubKeyX25519 pub) return (cert, PrivKeyX25519 priv) arbitraryCredX448 = do (pub, priv) <- arbitraryX448 cert <- arbitrarySignedCertificate (PubKeyX448 pub) return (cert, PrivKeyX448 priv) -- key wrapping in PWRIKEK is incompatible with CTR mode so we must never -- generate this combination notModeCTR params = case getContentEncryptionAlg params of CTR _ -> False _ -> True instance Arbitrary OriginatorInfo where arbitrary = OriginatorInfo <$> arbitrary <*> arbitrary instance Arbitrary CertificateChoice where arbitrary = oneof [ CertificateCertificate <$> arbitrary , CertificateOther <$> arbitrary ] instance Arbitrary RevocationInfoChoice where arbitrary = oneof [ RevocationInfoCRL <$> arbitrary , RevocationInfoOther <$> arbitrary ] instance Arbitrary OtherCertificateFormat where arbitrary = do oid <- arbitraryOID vals <- resize 3 $ listOf1 (OctetString <$> arbitrarySmall) return OtherCertificateFormat { otherCertFormat = oid , otherCertValues = vals } instance Arbitrary OtherRevocationInfoFormat where arbitrary = do oid <- arbitraryOID vals <- resize 3 $ listOf1 (OctetString <$> arbitrarySmall) return OtherRevocationInfoFormat { otherRevInfoFormat = oid , otherRevInfoValues = vals } cryptostore-0.3.1.0/tests/CMS/Tests.hs0000644000000000000000000003511107346545000015662 0ustar0000000000000000-- | CMS tests. module CMS.Tests (cmsTests) where import Control.Monad import qualified Data.ByteString as B import Data.String (fromString) import Data.Maybe (isNothing) import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.QuickCheck import Crypto.Store.CMS import Crypto.Store.PKCS8 import Crypto.Store.X509 (readSignedObject) import CMS.Instances import Util message :: B.ByteString message = fromString "hello, world\r\n" testKey :: Int -> B.ByteString testKey len = B.pack [0 .. toEnum (len - 1)] hasType :: ContentType -> ContentInfo -> Bool hasType t ci = t == getContentType ci verifyInnerMessage :: B.ByteString -> ContentInfo -> IO () verifyInnerMessage msg ci = do assertBool "unexpected inner type" (hasType DataType ci) let DataCI bs = ci assertEqual "inner message differs" msg bs dataTests :: TestTree dataTests = testGroup "Data" [ testCase "read" $ do cms <- readCMSFile path length cms @?= count forM_ cms (verifyInnerMessage message) , testCase "write" $ do bs <- B.readFile path let ciList = [DataCI message] writeCMSFileToMemory ciList @?= bs ] where path = testFile "cms-data.pem" count = 1 signedDataTests :: TestTree signedDataTests = signedDataAnyTests "SignedData" path getAttached where path = testFile "cms-signed-data.pem" signedDataDetachedTests :: TestTree signedDataDetachedTests = signedDataAnyTests "SignedDataDetached" path (getDetached message) where path = testFile "cms-signed-data-detached.pem" signedDataAnyTests :: TestName -> FilePath -> (SignedData (Encap EncapsulatedContent) -> IO (SignedData EncapsulatedContent)) -> TestTree signedDataAnyTests caseName path getInner = testCaseSteps caseName $ \step -> do cms <- readCMSFile path assertEqual "unexpected parse count" (length names) (length cms) forM_ (zip [0..] cms) $ \(index, ci) -> do let name = names !! index step ("verifying " ++ name) assertBool "unexpected type" (hasType SignedDataType ci) let SignedDataCI sdEncap = ci sd <- getInner sdEncap result <- verifySignedData withSignerKey sd assertRight result (verifyInnerMessage message) where names = [ "RSA" , "DSA" , "EC (named curve)" , "EC (explicit prime curve)" , "RSA-PSS" ] envelopedDataTests :: TestTree envelopedDataTests = testGroup "EnvelopedData" [ testKT "KTRI" path3 keys1 , testKA "KARI" path4 keys1 , test "KEKRI" path1 keys1 withRecipientKey , test "PWRI" path2 keys2 (\_ -> withRecipientPassword pwd) ] where test caseName path keys f = testCaseSteps caseName $ \step -> do cms <- readCMSFile path assertEqual "unexpected parse count" (length keys) (length cms) forM_ (zip [0..] cms) $ \(index, ci) -> do let (name, key) = keys !! index step ("testing " ++ name) ev <- getEnveloppedAttached ci result <- openEnvelopedData (f key) ev assertRight result (verifyInnerMessage message) testKT caseName path keys = testCaseSteps caseName $ \step -> do let rsaPath = testFile "rsa-unencrypted-pkcs8.pem" [Unprotected priv] <- readKeyFile rsaPath cms <- readCMSFile path assertEqual "unexpected parse count" (length modes * length keys) (length cms) let pairs = [ (c, m) | c <- map fst keys1, m <- modes ] forM_ (zip pairs cms) $ \((c, m), ci) -> do step ("testing " ++ c ++ " with " ++ m) ev <- getEnveloppedAttached ci result <- openEnvelopedData (withRecipientKeyTrans priv) ev assertRight result (verifyInnerMessage message) testKA caseName path keys = testCaseSteps caseName $ \step -> do let ecdsaKeyPath = testFile "ecdsa-p256-unencrypted-pkcs8.pem" ecdsaCertPath = testFile "ecdsa-p256-self-signed-cert.pem" [Unprotected priv] <- readKeyFile ecdsaKeyPath [cert] <- readSignedObject ecdsaCertPath cms <- readCMSFile path assertEqual "unexpected parse count" (length mds * length keys) (length cms) let pairs = [ (c, h) | c <- map fst keys, h <- mds ] forM_ (zip pairs cms) $ \((c, h), ci) -> do step ("testing " ++ c ++ " with " ++ h) ev <- getEnveloppedAttached ci result <- openEnvelopedData (withRecipientKeyAgree priv cert) ev assertRight result (verifyInnerMessage message) getEnveloppedAttached ci = do assertBool "unexpected type" (hasType EnvelopedDataType ci) let EnvelopedDataCI evEncap = ci getAttached evEncap path1 = testFile "cms-enveloped-kekri-data.pem" path2 = testFile "cms-enveloped-pwri-data.pem" path3 = testFile "cms-enveloped-ktri-data.pem" path4 = testFile "cms-enveloped-kari-data.pem" pwd = fromString "dontchangeme" keys2 = [ ("3DES_CBC", testKey 24) , ("AES128_CBC", testKey 16) , ("AES192_CBC", testKey 24) , ("AES256_CBC", testKey 32) , ("CAST5_CBC (128 bits)", testKey 16) , ("Camellia128_CBC", testKey 16) , ("RC2 (128 bits)", testKey 16) ] keys1 = keys2 ++ [ ("AES128_ECB", testKey 16) , ("AES192_ECB", testKey 24) , ("AES256_ECB", testKey 32) , ("Camellia128_ECB", testKey 16) ] modes = [ "RSAES-PKCS1" , "RSAES-OAEP" ] mds = [ "SHA1" , "SHA224" , "SHA256" , "SHA384" , "SHA512" ] digestedDataTests :: TestTree digestedDataTests = testCaseSteps "DigestedData" $ \step -> do cms <- readCMSFile path assertEqual "unexpected parse count" (length algs) (length cms) forM_ (zip [0..] cms) $ \(index, ci) -> do let (name, alg) = algs !! index step ("verifying " ++ name) assertBool "unexpected type" (hasType DigestedDataType ci) let DigestedDataCI ddEncap = ci dd <- getAttached ddEncap let result = digestVerify dd assertRight result (verifyInnerMessage message) step ("digesting " ++ name) let dd' = digestData alg (DataCI message) ci' = toAttachedCI dd' ci @?= ci' where path = testFile "cms-digested-data.pem" algs = [ ("MD5", DigestAlgorithm MD5) , ("SHA1", DigestAlgorithm SHA1) , ("SHA224", DigestAlgorithm SHA224) , ("SHA256", DigestAlgorithm SHA256) , ("SHA384", DigestAlgorithm SHA384) , ("SHA512", DigestAlgorithm SHA512) ] encryptedDataTests :: TestTree encryptedDataTests = testCaseSteps "EncryptedData" $ \step -> do cms <- readCMSFile path assertEqual "unexpected parse count" (length keys) (length cms) forM_ (zip [0..] cms) $ \(index, ci) -> do let (name, key) = keys !! index step ("decrypting " ++ name) assertBool "unexpected type" (hasType EncryptedDataType ci) let EncryptedDataCI edEncap = ci ed <- getAttached edEncap let result = decryptData key ed assertRight result (verifyInnerMessage message) step ("encrypting " ++ name) let params = edContentEncryptionParams ed ed' = encryptData key params [] (DataCI message) ci' = toAttachedCI <$> ed' Right ci @?= ci' where path = testFile "cms-encrypted-data.pem" keys = [ ("DES_CBC", testKey 8) , ("3DES_CBC", testKey 24) , ("AES128_CBC", testKey 16) , ("AES192_CBC", testKey 24) , ("AES256_CBC", testKey 32) , ("CAST5_CBC (40 bits)", testKey 5) , ("CAST5_CBC (128 bits)", testKey 16) , ("Camellia128_CBC", testKey 16) , ("RC2 (40 bits)", testKey 5) , ("RC2 (64 bits)", testKey 8) , ("RC2 (128 bits)", testKey 16) , ("DES_ECB", testKey 8) , ("AES128_ECB", testKey 16) , ("AES192_ECB", testKey 24) , ("AES256_ECB", testKey 32) , ("Camellia128_ECB", testKey 16) ] authEnvelopedDataTests :: TestTree authEnvelopedDataTests = testGroup "AuthEnvelopedData" [ testKT "KTRI" path3 , testKA "KARI" path4 , test "KEKRI" path1 withRecipientKey ] where test caseName path f = testCaseSteps caseName $ \step -> do cms <- readCMSFile path assertEqual "unexpected parse count" (length keys) (length cms) forM_ (zip [0..] cms) $ \(index, ci) -> do let (name, key) = keys !! index step ("testing " ++ name) ae <- getAuthEnveloppedAttached ci result <- openAuthEnvelopedData (f key) ae assertRight result (verifyInnerMessage message) testKT caseName path = testCaseSteps caseName $ \step -> do let rsaPath = testFile "rsa-unencrypted-pkcs8.pem" [Unprotected priv] <- readKeyFile rsaPath cms <- readCMSFile path assertEqual "unexpected parse count" (length modes * length keys) (length cms) let pairs = [ (c, m) | c <- map fst keys, m <- modes ] forM_ (zip pairs cms) $ \((c, m), ci) -> do step ("testing " ++ c ++ " with " ++ m) ae <- getAuthEnveloppedAttached ci result <- openAuthEnvelopedData (withRecipientKeyTrans priv) ae assertRight result (verifyInnerMessage message) testKA caseName path = testCaseSteps caseName $ \step -> do let ecdsaKeyPath = testFile "ecdsa-p256-unencrypted-pkcs8.pem" ecdsaCertPath = testFile "ecdsa-p256-self-signed-cert.pem" [Unprotected priv] <- readKeyFile ecdsaKeyPath [cert] <- readSignedObject ecdsaCertPath cms <- readCMSFile path assertEqual "unexpected parse count" (length mds * length keys) (length cms) let pairs = [ (c, h) | c <- map fst keys, h <- mds ] forM_ (zip pairs cms) $ \((c, h), ci) -> do step ("testing " ++ c ++ " with " ++ h) ae <- getAuthEnveloppedAttached ci result <- openAuthEnvelopedData (withRecipientKeyAgree priv cert) ae assertRight result (verifyInnerMessage message) getAuthEnveloppedAttached ci = do assertBool "unexpected type" (hasType AuthEnvelopedDataType ci) let AuthEnvelopedDataCI aeEncap = ci getAttached aeEncap path1 = testFile "cms-auth-enveloped-kekri-data.pem" path3 = testFile "cms-auth-enveloped-ktri-data.pem" path4 = testFile "cms-auth-enveloped-kari-data.pem" keys = [ ("AES128_GCM", testKey 16) , ("AES192_GCM", testKey 24) , ("AES256_GCM", testKey 32) ] modes = [ "RSAES-PKCS1" , "RSAES-OAEP" ] mds = [ "SHA1" , "SHA224" , "SHA256" , "SHA384" , "SHA512" ] propertyTests :: TestTree propertyTests = localOption (QuickCheckMaxSize 5) $ testGroup "properties" [ testProperty "marshalling" $ \l -> let bs = writeCMSFileToMemory l in label (sizeRange bs) $ l === readCMSFileFromMemory bs , testProperty "signing" $ \alg ci -> collect alg $ do (sigFns, verFn) <- scale succ (arbitrarySigVer alg) r <- signData sigFns ci let Right sd = r r' <- verifySignedData verFn sd return (Right ci === r') , testProperty "enveloping" $ \alg ci -> collect alg $ do (oinfo, key, envFns, devFn, attrs) <- getCommon alg r <- envelopData oinfo key alg envFns attrs ci let Right ev = r r' <- openEnvelopedData devFn ev return (Right ci === r') , testProperty "digesting" $ \alg ci -> collect alg $ let dd = digestData alg ci in Right ci === digestVerify dd , testProperty "encrypting" $ \alg ci -> collect alg $ do key <- generateKey alg attrs <- arbitraryAttributes let Right ed = encryptData key alg attrs ci return (Right ci === decryptData key ed) , testProperty "authenticating" $ \alg dig ci -> collect alg $ do (oinfo, key, envFns, devFn, uAttrs) <- getCommon alg aAttrs <- if isNothing dig then pure [] else arbitraryAttributes r <- generateAuthenticatedData oinfo key alg dig envFns aAttrs uAttrs ci let Right ad = r r' <- verifyAuthenticatedData devFn ad return (Right ci === r') , testProperty "enveloping with authentication" $ \alg ci -> collect alg $ do (oinfo, key, envFns, devFn, uAttrs) <- getCommon alg aAttrs <- arbitraryAttributes r <- authEnvelopData oinfo key alg envFns aAttrs uAttrs ci let Right ae = r r' <- openAuthEnvelopedData devFn ae return (Right ci === r') ] where sizeRange bs = let n = B.length bs `div` 1024 in show n ++ " .. " ++ show (n + 1) ++ " KB" getCommon :: HasKeySize params => params -> Gen (OriginatorInfo, B.ByteString, [ProducerOfRI Gen], ConsumerOfRI Gen, [Attribute]) getCommon alg = do oinfo <- arbitrary key <- generateKey alg (envFns, devFn) <- scale succ (arbitraryEnvDev key) attrs <- arbitraryAttributes return (oinfo, key, envFns, devFn, attrs) cmsTests :: TestTree cmsTests = testGroup "CMS" [ dataTests , signedDataTests , signedDataDetachedTests , envelopedDataTests , digestedDataTests , encryptedDataTests , authEnvelopedDataTests , propertyTests ] cryptostore-0.3.1.0/tests/Cipher/0000755000000000000000000000000007346545000015013 5ustar0000000000000000cryptostore-0.3.1.0/tests/Cipher/RC2.hs0000644000000000000000000001012407346545000015733 0ustar0000000000000000{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} -- | Test vectors from RFC 2268. module Cipher.RC2 (rc2Tests) where import Data.ByteString (ByteString, pack) import Crypto.Cipher.Types import Crypto.Error import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.QuickCheck import Crypto.Store.Cipher.RC2 import Util newtype Message = Message ByteString deriving (Show, Eq) instance Arbitrary Message where arbitrary = sized $ \n -> Message . pack <$> vector (8 * n) data Vector = Vector { vecEffectiveKeyLength :: Int , vecKey :: ByteString , vecPlaintext :: ByteString , vecCiphertext :: ByteString } vectors :: [Vector] vectors = [ Vector { vecEffectiveKeyLength = 63 , vecKey = "\x00\x00\x00\x00\x00\x00\x00\x00" , vecPlaintext = "\x00\x00\x00\x00\x00\x00\x00\x00" , vecCiphertext = "\xeb\xb7\x73\xf9\x93\x27\x8e\xff" } , Vector { vecEffectiveKeyLength = 64 , vecKey = "\xff\xff\xff\xff\xff\xff\xff\xff" , vecPlaintext = "\xff\xff\xff\xff\xff\xff\xff\xff" , vecCiphertext = "\x27\x8b\x27\xe4\x2e\x2f\x0d\x49" } , Vector { vecEffectiveKeyLength = 64 , vecKey = "\x30\x00\x00\x00\x00\x00\x00\x00" , vecPlaintext = "\x10\x00\x00\x00\x00\x00\x00\x01" , vecCiphertext = "\x30\x64\x9e\xdf\x9b\xe7\xd2\xc2" } , Vector { vecEffectiveKeyLength = 64 , vecKey = "\x88" , vecPlaintext = "\x00\x00\x00\x00\x00\x00\x00\x00" , vecCiphertext = "\x61\xa8\xa2\x44\xad\xac\xcc\xf0" } , Vector { vecEffectiveKeyLength = 64 , vecKey = "\x88\xbc\xa9\x0e\x90\x87\x5a" , vecPlaintext = "\x00\x00\x00\x00\x00\x00\x00\x00" , vecCiphertext = "\x6c\xcf\x43\x08\x97\x4c\x26\x7f" } , Vector { vecEffectiveKeyLength = 64 , vecKey = "\x88\xbc\xa9\x0e\x90\x87\x5a\x7f\x0f\x79\xc3\x84\x62\x7b\xaf\xb2" , vecPlaintext = "\x00\x00\x00\x00\x00\x00\x00\x00" , vecCiphertext = "\x1a\x80\x7d\x27\x2b\xbe\x5d\xb1" } , Vector { vecEffectiveKeyLength = 128 , vecKey = "\x88\xbc\xa9\x0e\x90\x87\x5a\x7f\x0f\x79\xc3\x84\x62\x7b\xaf\xb2" , vecPlaintext = "\x00\x00\x00\x00\x00\x00\x00\x00" , vecCiphertext = "\x22\x69\x55\x2a\xb0\xf8\x5c\xa6" } , Vector { vecEffectiveKeyLength = 129 , vecKey = "\x88\xbc\xa9\x0e\x90\x87\x5a\x7f\x0f\x79\xc3\x84\x62\x7b\xaf\xb2\x16\xf8\x0a\x6f\x85\x92\x05\x84\xc4\x2f\xce\xb0\xbe\x25\x5d\xaf\x1e" , vecPlaintext = "\x00\x00\x00\x00\x00\x00\x00\x00" , vecCiphertext = "\x5b\x78\xd3\xa4\x3d\xff\xf1\xf1" } ] testCipher :: forall cipher . BlockCipher cipher => String -> [Vector] -> cipher -> TestTree testCipher name vec _cipher = testGroup name [ testGroup "properties" [ testProperty "decrypt . encrypt == id" encryptDecryptProperty ] , testGroup "vectors" $ zipWith makeTest [1..] vec ] where initCipher :: BlockCipher cipher => ByteString -> cipher initCipher k = throwCryptoError (cipherInit k) encryptDecryptProperty :: TestKey cipher -> Message -> Property encryptDecryptProperty (Key key) (Message msg) = ecbDecrypt ctx (ecbEncrypt ctx msg) === msg where ctx = initCipher key makeTest :: Integer -> Vector -> TestTree makeTest i Vector{..} = testGroup (show i) [ testCase "Encrypt" (ecbEncrypt ctx vecPlaintext @?= vecCiphertext) , testCase "Decrypt" (ecbDecrypt ctx vecCiphertext @?= vecPlaintext) ] where ctx = throwCryptoError $ rc2WithEffectiveKeyLength vecEffectiveKeyLength vecKey rc2Tests :: TestTree rc2Tests = testCipher "Cipher.RC2" vectors (undefined :: RC2) cryptostore-0.3.1.0/tests/KeyWrap/0000755000000000000000000000000007346545000015163 5ustar0000000000000000cryptostore-0.3.1.0/tests/KeyWrap/AES.hs0000644000000000000000000001415207346545000016132 0ustar0000000000000000{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} -- | Test vectors from RFC 3394 and RFC 5649. module KeyWrap.AES (aeskwTests) where import Data.ByteString (ByteString, pack) import Crypto.Cipher.AES import Crypto.Cipher.Types import Crypto.Error import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.QuickCheck import Crypto.Store.KeyWrap.AES import Util newtype Message = Message ByteString deriving (Show, Eq) instance Arbitrary Message where arbitrary = sized $ \n -> Message . pack <$> vector (8 * n) newtype MessageP = MessageP ByteString deriving (Show, Eq) instance Arbitrary MessageP where arbitrary = MessageP . pack <$> listOf1 arbitrary data Vector = Vector { vecKey :: ByteString , vecPlaintext :: ByteString , vecCiphertext :: ByteString } vectors128 :: [Vector] vectors128 = [ Vector { vecKey = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" , vecPlaintext = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF" , vecCiphertext = "\x1F\xA6\x8B\x0A\x81\x12\xB4\x47\xAE\xF3\x4B\xD8\xFB\x5A\x7B\x82\x9D\x3E\x86\x23\x71\xD2\xCF\xE5" } ] vectors128P :: [Vector] vectors128P = [] vectors192 :: [Vector] vectors192 = [ Vector { vecKey = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17" , vecPlaintext = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF" , vecCiphertext = "\x96\x77\x8B\x25\xAE\x6C\xA4\x35\xF9\x2B\x5B\x97\xC0\x50\xAE\xD2\x46\x8A\xB8\xA1\x7A\xD8\x4E\x5D" } , Vector { vecKey = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17" , vecPlaintext = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x01\x02\x03\x04\x05\x06\x07" , vecCiphertext = "\x03\x1D\x33\x26\x4E\x15\xD3\x32\x68\xF2\x4E\xC2\x60\x74\x3E\xDC\xE1\xC6\xC7\xDD\xEE\x72\x5A\x93\x6B\xA8\x14\x91\x5C\x67\x62\xD2" } ] vectors192P :: [Vector] vectors192P = [ Vector { vecKey = "\x58\x40\xdf\x6e\x29\xb0\x2a\xf1\xab\x49\x3b\x70\x5b\xf1\x6e\xa1\xae\x83\x38\xf4\xdc\xc1\x76\xa8" , vecPlaintext = "\xc3\x7b\x7e\x64\x92\x58\x43\x40\xbe\xd1\x22\x07\x80\x89\x41\x15\x50\x68\xf7\x38" , vecCiphertext = "\x13\x8b\xde\xaa\x9b\x8f\xa7\xfc\x61\xf9\x77\x42\xe7\x22\x48\xee\x5a\xe6\xae\x53\x60\xd1\xae\x6a\x5f\x54\xf3\x73\xfa\x54\x3b\x6a" } , Vector { vecKey = "\x58\x40\xdf\x6e\x29\xb0\x2a\xf1\xab\x49\x3b\x70\x5b\xf1\x6e\xa1\xae\x83\x38\xf4\xdc\xc1\x76\xa8" , vecPlaintext = "\x46\x6f\x72\x50\x61\x73\x69" , vecCiphertext = "\xaf\xbe\xb0\xf0\x7d\xfb\xf5\x41\x92\x00\xf2\xcc\xb5\x0b\xb2\x4f" } ] vectors256 :: [Vector] vectors256 = [ Vector { vecKey = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" , vecPlaintext = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF" , vecCiphertext = "\x64\xE8\xC3\xF9\xCE\x0F\x5B\xA2\x63\xE9\x77\x79\x05\x81\x8A\x2A\x93\xC8\x19\x1E\x7D\x6E\x8A\xE7" } , Vector { vecKey = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" , vecPlaintext = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x01\x02\x03\x04\x05\x06\x07" , vecCiphertext = "\xA8\xF9\xBC\x16\x12\xC6\x8B\x3F\xF6\xE6\xF4\xFB\xE3\x0E\x71\xE4\x76\x9C\x8B\x80\xA3\x2C\xB8\x95\x8C\xD5\xD1\x7D\x6B\x25\x4D\xA1" } , Vector { vecKey = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" , vecPlaintext = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" , vecCiphertext = "\x28\xC9\xF4\x04\xC4\xB8\x10\xF4\xCB\xCC\xB3\x5C\xFB\x87\xF8\x26\x3F\x57\x86\xE2\xD8\x0E\xD3\x26\xCB\xC7\xF0\xE7\x1A\x99\xF4\x3B\xFB\x98\x8B\x9B\x7A\x02\xDD\x21" } ] vectors256P :: [Vector] vectors256P = [] testCipher :: forall cipher . BlockCipher cipher => [Vector] -> [Vector] -> cipher -> TestTree testCipher vec vecP cipher = testGroup (cipherName cipher) [ testGroup "properties" [ testProperty "unwrap . wrap == id" wrapUnwrapProperty , testProperty "unwrapPad . wrapPad == id" wrapUnwrapPadProperty ] , testGroup "vectors" $ zipWith makeTest [1..] vec ++ zipWith makeTestP [1..] vecP ] where initCipher :: BlockCipher cipher => ByteString -> cipher initCipher k = throwCryptoError (cipherInit k) wrapUnwrapProperty :: TestKey cipher -> Message -> Property wrapUnwrapProperty (Key key) (Message msg) = (wrap ctx msg >>= unwrap ctx) === Right msg where ctx = initCipher key makeTest :: Integer -> Vector -> TestTree makeTest i Vector{..} = testGroup (show i) [ testCase "Wrap" (wrap ctx vecPlaintext @?= Right vecCiphertext) , testCase "Unwrap" (unwrap ctx vecCiphertext @?= Right vecPlaintext) ] where ctx = initCipher vecKey wrapUnwrapPadProperty :: TestKey cipher -> MessageP -> Property wrapUnwrapPadProperty (Key key) (MessageP msg) = (wrapPad ctx msg >>= unwrapPad ctx) === Right msg where ctx = initCipher key makeTestP :: Integer -> Vector -> TestTree makeTestP i Vector{..} = testGroup ("Pad" ++ show i) [ testCase "Wrap" (wrapPad ctx vecPlaintext @?= Right vecCiphertext) , testCase "Unwrap" (unwrapPad ctx vecCiphertext @?= Right vecPlaintext) ] where ctx = initCipher vecKey aeskwTests :: TestTree aeskwTests = testGroup "KeyWrap.AES" [ testCipher vectors128 vectors128P (undefined :: AES128) , testCipher vectors192 vectors192P (undefined :: AES192) , testCipher vectors256 vectors256P (undefined :: AES256) ] cryptostore-0.3.1.0/tests/KeyWrap/RC2.hs0000644000000000000000000000644507346545000016116 0ustar0000000000000000{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} -- | Test vectors from RFC 3217. module KeyWrap.RC2 (rc2kwTests) where import Data.ByteString (ByteString) import qualified Data.ByteString as B import Crypto.Cipher.Types import Crypto.Error import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.QuickCheck import Crypto.Store.Cipher.RC2 import Crypto.Store.Error import Crypto.Store.KeyWrap.RC2 import X509.Instances () -- for instance MonadRandom Gen import Util newtype Message = Message ByteString deriving (Show, Eq) instance Arbitrary Message where arbitrary = Message . B.pack <$> (choose (0, 255) >>= vector) data Vector = Vector { vecEKL :: Int , vecKey :: ByteString , vecPad :: ByteString , vecIV :: ByteString , vecPlaintext :: ByteString , vecCiphertext :: ByteString } vectors :: [Vector] vectors = [ Vector { vecEKL = 40 , vecKey = "\xfd\x04\xfd\x08\x06\x07\x07\xfb\x00\x03\xfe\xff\xfd\x02\xfe\x05" , vecPad = "\x48\x45\xcc\xe7\xfd\x12\x50" , vecIV = "\xc7\xd9\x00\x59\xb2\x9e\x97\xf7" , vecPlaintext = "\xb7\x0a\x25\xfb\xc9\xd8\x6a\x86\x05\x0c\xe0\xd7\x11\xea\xd4\xd9" , vecCiphertext = "\x70\xe6\x99\xfb\x57\x01\xf7\x83\x33\x30\xfb\x71\xe8\x7c\x85\xa4\x20\xbd\xc9\x9a\xf0\x5d\x22\xaf\x5a\x0e\x48\xd3\x5f\x31\x38\x98\x6c\xba\xaf\xb4\xb2\x8d\x4f\x35" } , Vector { vecEKL = 128 -- from RFC Errata , vecKey = "\xfd\x04\xfd\x08\x06\x07\x07\xfb\x00\x03\xfe\xff\xfd\x02\xfe\x05" , vecPad = "\x48\x45\xcc\xe7\xfd\x12\x50" , vecIV = "\xc7\xd9\x00\x59\xb2\x9e\x97\xf7" , vecPlaintext = "\xb7\x0a\x25\xfb\xc9\xd8\x6a\x86\x05\x0c\xe0\xd7\x11\xea\xd4\xd9" , vecCiphertext = "\xf4\xd8\x02\x1c\x1e\xa4\x63\xd2\x17\xa9\xeb\x69\x29\xff\xa5\x77\x36\xd3\xe2\x03\x86\xc9\x09\x93\x83\x5b\x4b\xe4\xad\x8d\x8a\x1b\xc6\x3b\x25\xde\x2b\xf7\x79\x93" } ] rc2kwTests :: TestTree rc2kwTests = testGroup "KeyWrap.RC2" [ testGroup "properties" [ testProperty "unwrap . wrap == id" wrapUnwrapProperty ] , testGroup "vectors" (zipWith makeTest [1..] vectors) ] where initCipher :: Int -> ByteString -> RC2 initCipher ekl k = throwCryptoError (rc2WithEffectiveKeyLength ekl k) wrapUnwrapProperty :: TestKey RC2 -> TestIV RC2 -> Message -> Gen Property wrapUnwrapProperty (Key key) (IV ivBs) (Message msg) = do ekl <- choose (1, 1024) let ctx = initCipher ekl key wrapped <- wrap ctx iv msg return $ (wrapped >>= unwrap ctx) === Right msg where Just iv = makeIV ivBs makeTest :: Integer -> Vector -> TestTree makeTest i Vector{..} = testGroup (show i) [ testCase "Wrap" (doWrap ctx iv vecPlaintext @?= Right vecCiphertext) , testCase "Unwrap" (unwrap ctx vecCiphertext @?= Right vecPlaintext) ] where ctx = initCipher vecEKL vecKey Just iv = makeIV vecIV doWrap = wrap' Left withRandomPad withRandomPad f len | B.length vecPad /= len = Left (InvalidInput "unexpected length") | otherwise = Right (f vecPad) cryptostore-0.3.1.0/tests/KeyWrap/TripleDES.hs0000644000000000000000000000541607346545000017320 0ustar0000000000000000{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} -- | Test vectors from RFC 3217. module KeyWrap.TripleDES (tripledeskwTests) where import Data.ByteString (ByteString, pack) import Crypto.Cipher.TripleDES import Crypto.Cipher.Types import Crypto.Error import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.QuickCheck import Crypto.Store.KeyWrap.TripleDES import Util newtype Message = Message ByteString deriving (Show, Eq) instance Arbitrary Message where arbitrary = Message . pack <$> vector 24 data Vector = Vector { vecKey :: ByteString , vecIV :: ByteString , vecPlaintext :: ByteString , vecCiphertext :: ByteString } vectorsEDE3 :: [Vector] vectorsEDE3 = [ Vector { vecKey = "\x25\x5e\x0d\x1c\x07\xb6\x46\xdf\xb3\x13\x4c\xc8\x43\xba\x8a\xa7\x1f\x02\x5b\x7c\x08\x38\x25\x1f" , vecIV = "\x5d\xd4\xcb\xfc\x96\xf5\x45\x3b" , vecPlaintext = "\x29\x23\xbf\x85\xe0\x6d\xd6\xae\x52\x91\x49\xf1\xf1\xba\xe9\xea\xb3\xa7\xda\x3d\x86\x0d\x3e\x98" , vecCiphertext = "\x69\x01\x07\x61\x8e\xf0\x92\xb3\xb4\x8c\xa1\x79\x6b\x23\x4a\xe9\xfa\x33\xeb\xb4\x15\x96\x04\x03\x7d\xb5\xd6\xa8\x4e\xb3\xaa\xc2\x76\x8c\x63\x27\x75\xa4\x67\xd4" } ] vectorsEEE3 :: [Vector] vectorsEEE3 = [] vectorsEDE2 :: [Vector] vectorsEDE2 = [] vectorsEEE2 :: [Vector] vectorsEEE2 = [] testCipher :: forall cipher . BlockCipher cipher => [Vector] -> cipher -> TestTree testCipher vectors cipher = testGroup (cipherName cipher) [ localOption (QuickCheckTests 10) $ testGroup "properties" [ testProperty "unwrap . wrap == id" wrapUnwrapProperty ] , testGroup "vectors" (zipWith makeTest [1..] vectors) ] where initCipher :: BlockCipher cipher => ByteString -> cipher initCipher k = throwCryptoError (cipherInit k) wrapUnwrapProperty :: TestKey cipher -> TestIV cipher -> Message -> Property wrapUnwrapProperty (Key key) (IV ivBs) (Message msg) = (wrap ctx iv msg >>= unwrap ctx) === Right msg where ctx = initCipher key Just iv = makeIV ivBs makeTest :: Integer -> Vector -> TestTree makeTest i Vector{..} = testGroup (show i) [ testCase "Wrap" (wrap ctx iv vecPlaintext @?= Right vecCiphertext) , testCase "Unwrap" (unwrap ctx vecCiphertext @?= Right vecPlaintext) ] where ctx = initCipher vecKey Just iv = makeIV vecIV tripledeskwTests :: TestTree tripledeskwTests = testGroup "KeyWrap.TripleDES" [ testCipher vectorsEDE3 (undefined :: DES_EDE3) , testCipher vectorsEEE3 (undefined :: DES_EEE3) , testCipher vectorsEDE2 (undefined :: DES_EDE2) , testCipher vectorsEEE2 (undefined :: DES_EEE2) ] cryptostore-0.3.1.0/tests/0000755000000000000000000000000007346545000013601 5ustar0000000000000000cryptostore-0.3.1.0/tests/Main.hs0000644000000000000000000000071207346545000015021 0ustar0000000000000000-- | cryptostore test suite. module Main (main) where import Test.Tasty import KeyWrap.AES import KeyWrap.TripleDES import KeyWrap.RC2 import Cipher.RC2 import CMS.Tests import PKCS12.Tests import PKCS8.Tests import X509.Tests -- | Run the test suite. main :: IO () main = defaultMain $ testGroup "cryptostore" [ aeskwTests , tripledeskwTests , rc2kwTests , rc2Tests , cmsTests , x509Tests , pkcs8Tests , pkcs12Tests ] cryptostore-0.3.1.0/tests/PKCS12/0000755000000000000000000000000007346545000014504 5ustar0000000000000000cryptostore-0.3.1.0/tests/PKCS12/Instances.hs0000644000000000000000000000426407346545000016775 0ustar0000000000000000{-# OPTIONS_GHC -fno-warn-orphans #-} -- | Orphan instances. module PKCS12.Instances ( arbitraryPassword , arbitraryAlias , arbitraryIntegrityParams , arbitraryPKCS12 ) where import qualified Data.ByteArray as B import Data.ByteString (ByteString) import Data.Semigroup import Test.Tasty.QuickCheck import Crypto.Store.PKCS12 import Crypto.Store.PKCS5 import CMS.Instances import PKCS8.Instances () arbitrarySmall :: Gen ByteString arbitrarySmall = resize 10 (B.pack <$> arbitrary) arbitraryAlias :: Gen String arbitraryAlias = resize 16 asciiChar where asciiChar = listOf $ choose ('\x20','\x7f') arbitraryIntegrityParams :: Gen IntegrityParams arbitraryIntegrityParams = (,) <$> arbitraryIntegrityDigest <*> arbitrary arbitraryPKCS12 :: ProtectionPassword -> Gen PKCS12 arbitraryPKCS12 pwd = do p <- one ps <- listOf one return (foldr (<>) p ps) where one = oneof [ unencrypted <$> arbitrary , arbitrary >>= arbitraryEncrypted ] arbitraryEncrypted sc = do alg <- arbitrary case encrypted alg pwd sc of Left e -> error ("failed generating PKCS12: " ++ show e) Right aSafe -> return aSafe instance Arbitrary SafeContents where arbitrary = SafeContents <$> arbitrary instance Arbitrary info => Arbitrary (Bag info) where arbitrary = do info <- arbitrary attrs <- arbitraryAttributes return Bag { bagInfo = info, bagAttributes = attrs } instance Arbitrary CertInfo where arbitrary = CertX509 <$> arbitrary instance Arbitrary CRLInfo where arbitrary = CRLX509 <$> arbitrary instance Arbitrary SafeInfo where arbitrary = oneof [ KeyBag <$> arbitrary , PKCS8ShroudedKeyBag <$> arbitraryShrouded , CertBag <$> arbitrary , CRLBag <$> arbitrary --, SecretBag <$> arbitrary , SafeContentsBag <$> arbitrary ] arbitraryShrouded :: Gen PKCS5 arbitraryShrouded = do alg <- arbitrary bs <- arbitrarySmall -- fake content, tested with PKCS8 return PKCS5 { encryptionAlgorithm = alg, encryptedData = bs } cryptostore-0.3.1.0/tests/PKCS12/Tests.hs0000644000000000000000000001145607346545000016151 0ustar0000000000000000-- | PKCS #12 tests. module PKCS12.Tests (pkcs12Tests) where import Control.Monad (forM_) import Data.PEM (pemContent) import Data.String (fromString) import Crypto.Store.PKCS12 import Crypto.Store.PKCS8 import Crypto.Store.X509 (readSignedObject) import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.QuickCheck import Util import PKCS12.Instances import X509.Instances testType :: TestName -> String -> TestTree testType caseName prefix = testCaseSteps caseName $ \step -> do let fKey = testFile (prefix ++ "-unencrypted-pkcs8.pem") fCert = testFile (prefix ++ "-self-signed-cert.pem") p12 = testFile (prefix ++ "-pkcs12.pem") step "Reading PKCS #12 files" pems <- readPEMs p12 length pems @?= length names step "Reading private key" [Unprotected key] <- readKeyFile fKey step "Reading certificate" certs <- readSignedObject fCert forM_ (zip names pems) $ \(name, pem) -> do let r = readP12FileFromMemory (pemContent pem) assertRight r $ \integrity -> assertRight (recoverAuthenticated pwd integrity) $ \(ppwd, privacy) -> assertRight (recover ppwd $ unPKCS12 privacy) $ \scs -> do step ("Testing " ++ name) recover ppwd (getAllSafeKeys scs) @?= Right [key] getAllSafeX509Certs scs @?= certs where pwd = fromString "dontchangeme" nameIntegrity n = "integrity with " ++ n namePrivacy t n = t ++ " privacy with " ++ n integrityNames = map nameIntegrity integrityModes privacyNames t = ("without " ++ t ++ " privacy") : map (namePrivacy t) privacyModes names = [ "without integrity" ] ++ integrityNames ++ privacyNames "certificate" ++ privacyNames "private-key" integrityModes = [ "SHA-1" , "SHA-256" , "SHA-384" ] privacyModes = [ "aes-128-cbc" , "PBE-SHA1-RC2-128" , "PBE-SHA1-RC2-40" ] testEmptyPassword :: TestTree testEmptyPassword = testCaseSteps "empty password" $ \step -> do step "Reading PKCS #12 files" pems <- readPEMs path length pems @?= length infos forM_ (zip infos pems) $ \((name, numKeys, numCerts), pem) -> do let r = readP12FileFromMemory (pemContent pem) assertRight r $ \integrity -> assertRight (recoverAuthenticated pwd integrity) $ \(ppwd, privacy) -> assertRight (recover ppwd $ unPKCS12 privacy) $ \scs -> do step ("Testing " ++ name) assertRight (recover ppwd $ getAllSafeKeys scs) $ \keys -> length keys @?= numKeys length (getAllSafeX509Certs scs) @?= numCerts where pwd = fromString "" path = testFile "pkcs12-empty-password.pem" infos = [ ("Windows Certificate Export Wizard", 1, 2) , ("OpenSSL", 1, 1) , ("GnuTLS with --empty-password", 1, 1) , ("GnuTLS with --null-password", 1, 1) ] propertyTests :: TestTree propertyTests = localOption (QuickCheckMaxSize 5) $ testGroup "properties" [ testProperty "marshalling" $ do pE <- arbitrary c <- arbitraryPKCS12 pE let r = readP12FileFromMemory $ writeUnprotectedP12FileToMemory c unused = fromString "not-used" return $ Right (Right c) === (fmap snd . recoverAuthenticated unused <$> r) , testProperty "marshalling with authentication" $ do params <- arbitraryIntegrityParams c <- arbitrary >>= arbitraryPKCS12 pI <- arbitrary let r = readP12FileFromMemory <$> writeP12FileToMemory params pI c p = fromProtectionPassword pI return $ Right (Right (Right (pI, c))) === (fmap (recoverAuthenticated p) <$> r) , localOption (QuickCheckTests 20) $ testProperty "converting credentials" $ \pChain pKey privKey -> testCredConv privKey toCredential (fromCredential pChain pKey) , localOption (QuickCheckTests 20) $ testProperty "converting named credentials" $ \pChain pKey privKey -> do name <- arbitraryAlias testCredConv privKey (toNamedCredential name) (fromNamedCredential name pChain pKey) ] where testCredConv privKey to from = do pwd <- arbitrary chain <- arbitrary >>= arbitraryCertificateChain chain' <- shuffleCertificateChain chain let cred = (chain, privKey) r = from pwd (chain', privKey) >>= recover pwd . to return $ Right (Just cred) === r pkcs12Tests :: TestTree pkcs12Tests = testGroup "PKCS12" [ testType "RSA" "rsa" , testType "Ed25519" "ed25519" , testEmptyPassword , propertyTests ] cryptostore-0.3.1.0/tests/PKCS8/0000755000000000000000000000000007346545000014431 5ustar0000000000000000cryptostore-0.3.1.0/tests/PKCS8/Instances.hs0000644000000000000000000000341607346545000016720 0ustar0000000000000000{-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- | Orphan instances. module PKCS8.Instances ( arbitraryPassword ) where import Data.X509 import Test.Tasty.QuickCheck import Crypto.Store.CMS import Crypto.Store.PKCS5 import Crypto.Store.PKCS8 import CMS.Instances instance Arbitrary ProtectionPassword where arbitrary = oneof [ return emptyNotTerminated , toProtectionPassword <$> arbitraryPassword ] instance Arbitrary PBEParameter where arbitrary = do salt <- generateSalt 8 PBEParameter salt <$> choose (1,512) instance Arbitrary PBES2Parameter where arbitrary = PBES2Parameter <$> arbitrary <*> arbitrary instance Arbitrary EncryptionScheme where arbitrary = oneof [ PBES2 <$> arbitrary , PBE_MD5_DES_CBC <$> arbitrary , PBE_SHA1_DES_CBC <$> arbitrary , PBE_SHA1_RC4_128 <$> arbitrary , PBE_SHA1_RC4_40 <$> arbitrary , PBE_SHA1_DES_EDE3_CBC <$> arbitrary , PBE_SHA1_DES_EDE2_CBC <$> arbitrary , PBE_SHA1_RC2_128 <$> arbitrary , PBE_SHA1_RC2_40 <$> arbitrary ] instance Arbitrary PrivateKeyFormat where arbitrary = elements [ TraditionalFormat, PKCS8Format ] instance Arbitrary (FormattedKey PrivKey) where arbitrary = do key <- arbitrary fmt <- if pkcs8only key then return PKCS8Format else arbitrary return (FormattedKey fmt key) pkcs8only :: PrivKey -> Bool pkcs8only (PrivKeyX25519 _) = True pkcs8only (PrivKeyX448 _) = True pkcs8only (PrivKeyEd25519 _) = True pkcs8only (PrivKeyEd448 _) = True pkcs8only _ = False cryptostore-0.3.1.0/tests/PKCS8/Tests.hs0000644000000000000000000001051407346545000016070 0ustar0000000000000000-- | PKCS #8 tests. module PKCS8.Tests (pkcs8Tests) where import qualified Data.ByteString as B import Data.String (fromString) import Crypto.Store.PKCS8 import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.QuickCheck import Util import PKCS8.Instances () data KeyTestType = InnerOuter | OnlyOuter keyTests :: KeyTestType -> String -> TestTree keyTests InnerOuter prefix = testGroup "PrivateKey" [ testCase "read outer" $ do kOuter <- readKeyFile fOuter length kOuter @?= 1 , testCase "read inner" $ do kInner <- readKeyFile fInner length kInner @?= 1 , testCase "same key" $ do kInner <- readKeyFile fInner kOuter <- readKeyFile fOuter assertBool "keys differ" $ let [Unprotected kI] = kInner [Unprotected kO] = kOuter in kI == kO , testCase "write outer" $ do bs <- B.readFile fOuter let kOuter = readKeyFileFromMemory bs [Unprotected kO] = kOuter writeKeyFileToMemory PKCS8Format [kO] @?= bs , testCase "write inner" $ do bs <- B.readFile fInner let kInner = readKeyFileFromMemory bs [Unprotected kI] = kInner writeKeyFileToMemory TraditionalFormat [kI] @?= bs ] where fInner = testFile (prefix ++ "-unencrypted-trad.pem") fOuter = testFile (prefix ++ "-unencrypted-pkcs8.pem") keyTests OnlyOuter prefix = testGroup "PrivateKey" [ testCase "read" $ do kOuter <- readKeyFile fOuter length kOuter @?= 1 , testCase "write" $ do bs <- B.readFile fOuter let kOuter = readKeyFileFromMemory bs [Unprotected kO] = kOuter writeKeyFileToMemory PKCS8Format [kO] @?= bs ] where fOuter = testFile (prefix ++ "-unencrypted-pkcs8.pem") encryptedKeyTests :: String -> TestTree encryptedKeyTests prefix = testGroup "EncryptedPrivateKey" [ keyTest "PBES1" "pbes1" 8 , keyTest "PBKDF2" "pbkdf2" 7 , keyTest "Scrypt" "scrypt" 3 ] where pwd = fromString "dontchangeme" keyTest name suffix count = let fE = testFile (prefix ++ "-encrypted-" ++ suffix ++ ".pem") fU = testFile (prefix ++ "-unencrypted-pkcs8.pem") in testGroup name [ testCase "read unencrypted" $ do kU <- readKeyFile fU length kU @?= 1 , testCase "read encrypted" $ do kE <- readKeyFile fE length kE @?= count , testCase "same keys" $ do kE <- readKeyFile fE kU <- readKeyFile fU assertBool "some keys differ" $ let [Unprotected key] = kU in all (\(Protected getKey) -> getKey pwd == Right key) kE ] testType :: TestName -> KeyTestType -> String -> TestTree testType name ty prefix = testGroup name [ keyTests ty prefix , encryptedKeyTests prefix ] propertyTests :: TestTree propertyTests = localOption (QuickCheckMaxSize 5) $ testGroup "properties" [ testProperty "marshalling" $ \fmt l -> let r = readKeyFileFromMemory $ writeKeyFileToMemory fmt l in map Right l === map (recover $ fromString "not-used") r , testProperty "marshalling with encryption" $ \es k -> do p <- arbitrary let r = readKeyFileFromMemory <$> writeEncryptedKeyFileToMemory es p k return $ Right [Right k] === (map (recover p) <$> r) ] pkcs8Tests :: TestTree pkcs8Tests = testGroup "PKCS8" [ testType "RSA" InnerOuter "rsa" , testType "DSA" InnerOuter "dsa" , testType "EC (named curve)" InnerOuter "ecdsa-p256" , testType "EC (explicit prime curve)" InnerOuter "ecdsa-epc" , testType "X25519" OnlyOuter "x25519" , testType "X448" OnlyOuter "x448" , testType "Ed25519" OnlyOuter "ed25519" , testType "Ed448" OnlyOuter "ed448" , propertyTests ] cryptostore-0.3.1.0/tests/Util.hs0000644000000000000000000000361407346545000015056 0ustar0000000000000000{-# LANGUAGE ScopedTypeVariables #-} -- | Test utilities. module Util ( assertJust , assertRight , getAttached , getDetached , testFile , TestKey(..) , TestIV(..) ) where import Control.Monad (when) import Data.ByteString (ByteString, pack) import Data.Maybe (isNothing) import Crypto.Cipher.Types import Crypto.Store.CMS import Test.Tasty.HUnit import Test.Tasty.QuickCheck assertJust :: Maybe a -> (a -> Assertion) -> Assertion assertJust (Just a) f = f a assertJust Nothing _ = assertFailure "expecting Just but got Nothing" assertRight :: Show a => Either a b -> (b -> Assertion) -> Assertion assertRight (Right b) f = f b assertRight (Left val) _ = assertFailure ("expecting Right but got: Left " ++ show val) getAttached :: Encapsulates struct => struct (Encap a) -> IO (struct a) getAttached e = do let m = fromAttached e when (isNothing m) $ assertFailure "expecting attached but got detached content" let Just r = m in return r getDetached :: Encapsulates struct => a -> struct (Encap a) -> IO (struct a) getDetached c e = do let m = fromDetached c e when (isNothing m) $ assertFailure "expecting detached but got attached content" let Just r = m in return r testFile :: String -> FilePath testFile name = "tests/files/" ++ name newtype TestKey cipher = Key ByteString deriving (Show, Eq) instance Cipher cipher => Arbitrary (TestKey cipher) where arbitrary = Key . pack <$> case cipherKeySize cipher of KeySizeFixed len -> vector len KeySizeRange a b -> choose (a, b) >>= vector KeySizeEnum list -> elements list >>= vector where cipher = undefined :: cipher newtype TestIV cipher = IV ByteString deriving (Show, Eq) instance BlockCipher cipher => Arbitrary (TestIV cipher) where arbitrary = IV . pack <$> vector (blockSize cipher) where cipher = undefined :: cipher cryptostore-0.3.1.0/tests/X509/0000755000000000000000000000000007346545000014246 5ustar0000000000000000cryptostore-0.3.1.0/tests/X509/Instances.hs0000644000000000000000000003127107346545000016535 0ustar0000000000000000{-# OPTIONS_GHC -fno-warn-orphans #-} -- | Orphan instances. module X509.Instances ( arbitraryOID , arbitraryRSA , arbitraryLargeRSA , arbitraryDSA , arbitraryNamedEC , arbitraryX25519 , arbitraryX448 , arbitraryEd25519 , arbitraryEd448 , arbitrarySignedCertificate , arbitraryCertificateChain , shuffleCertificateChain ) where import Control.Monad (zipWithM) import Data.ASN1.Types import qualified Data.ByteArray as B import Data.Hourglass import Data.List (nub) import Data.X509 import Test.Tasty.QuickCheck import Crypto.Number.Serialize (i2ospOf_) import qualified Crypto.PubKey.Curve25519 as X25519 import qualified Crypto.PubKey.Curve448 as X448 import qualified Crypto.PubKey.DSA as DSA import qualified Crypto.PubKey.ECC.ECDSA as ECDSA import qualified Crypto.PubKey.ECC.Generate as ECC import qualified Crypto.PubKey.ECC.Types as ECC import qualified Crypto.PubKey.Ed25519 as Ed25519 import qualified Crypto.PubKey.Ed448 as Ed448 import qualified Crypto.PubKey.RSA as RSA import Crypto.Random -- Warning: not a cryptographic implementation, used for tests only instance MonadRandom Gen where getRandomBytes n = B.pack <$> vector n arbitraryOID :: Gen [Integer] arbitraryOID = do o1 <- choose (0,6) o2 <- choose (0,15) os <- resize 5 $ listOf (getPositive <$> arbitrary) return (o1 : o2 : os) arbitraryDN :: Gen DistinguishedName arbitraryDN = DistinguishedName <$> resize 5 (listOf1 arbitraryDE) where arbitrarySE = elements [IA5, UTF8] arbitraryDE = (,) <$> arbitraryOID <*> arbitraryCS arbitraryCS = ASN1CharacterString <$> arbitrarySE <*> arbitraryBS arbitraryBS = resize 16 (B.pack <$> listOf1 arbitrary) instance Arbitrary PubKey where arbitrary = oneof [ PubKeyRSA . fst <$> arbitraryRSA , PubKeyDSA . fst <$> arbitraryDSA , PubKeyEC . fst <$> arbitraryNamedEC --, PubKeyEC . fst <$> arbitraryExplicitPrimeCurve , PubKeyX25519 . fst <$> arbitraryX25519 , PubKeyX448 . fst <$> arbitraryX448 , PubKeyEd25519 . fst <$> arbitraryEd25519 , PubKeyEd448 . fst <$> arbitraryEd448 ] instance Arbitrary PrivKey where arbitrary = oneof [ PrivKeyRSA . snd <$> arbitraryRSA , PrivKeyDSA . snd <$> arbitraryDSA , PrivKeyEC . snd <$> arbitraryNamedEC , PrivKeyEC . snd <$> arbitraryExplicitPrimeCurve , PrivKeyX25519 . snd <$> arbitraryX25519 , PrivKeyX448 . snd <$> arbitraryX448 , PrivKeyEd25519 . snd <$> arbitraryEd25519 , PrivKeyEd448 . snd <$> arbitraryEd448 ] arbitraryRSA :: Gen (RSA.PublicKey, RSA.PrivateKey) arbitraryRSA = do n <- elements [ 768, 1024 ] -- enough bits to sign with SHA-512 e <- elements [ 3, 0x10001 ] RSA.generate (n `div` 8) e arbitraryLargeRSA :: Gen (RSA.PublicKey, RSA.PrivateKey) arbitraryLargeRSA = do n <- elements [ 1792, 2048 ] -- enough bits for RSA-OAEP with SHA-512 e <- elements [ 3, 0x10001 ] RSA.generate (n `div` 8) e arbitraryDSA :: Gen (DSA.PublicKey, DSA.PrivateKey) arbitraryDSA = do x <- DSA.generatePrivate params let y = DSA.calculatePublic params x priv = DSA.PrivateKey { DSA.private_params = params, DSA.private_x = x } pub = DSA.PublicKey { DSA.public_params = params, DSA.public_y = y } return (pub, priv) where -- DSA parameters were generated using 'openssl dsaparam -C 2048' params = DSA.Params { DSA.params_p = 0x9994B9B1FC22EC3A5F607B5130D314F35FC8D387015A6D8FA2B56D3CC1F13FE330A631DBC765CEFFD6986BDEB8512580BBAD93D56EE7A8997DB9C65C29313FBC5077DB6F1E9D9E6D3499F997F09C8CF8ECC9E5F38DC34C3D656CFDF463893DDF9E246E223D7E5C4E86F54426DDA5DE112FCEDBFB5B6D6F7C76ED190EA1A7761CA561E8E5803F9D616DAFF25E2CCD4011A6D78D5CE8ED28CC2D865C7EC01508BA96FBD1F8BB5E517B6A5208A90AC2D3DCAE50281C02510B86C16D449465CD4B3754FD91AA19031282122A25C68292F033091FCB9DEBDE0D220F81F7EE4AB6581D24BE48204AF3DA52BDB944DA53B76148055395B30954735DC911574D360C953B , DSA.params_g = 0x10E51AEA37880C5E52DD477ED599D55050C47012D038B9E4B3199C9DE9A5B873B1ABC8B954F26AFEA6C028BCE1783CFE19A88C64E4ED6BFD638802A78457A5C25ABEA98BE9C6EF18A95504C324315EABE7C1EA50E754591E3EFD3D33D4AE47F82F8978ABC871C135133767ACC60683F065430C749C43893D73596B12D5835A78778D0140B2F63B32A5658308DD5BA6BBC49CF6692929FA6A966419404F9A2C216860E3F339EDDB49AD32C294BDB4C9C6BB0D1CC7B691C65968C3A0A5106291CD3810147C8A16B4BFE22968AD9D3890733F4AA9ACD8687A5B981653A4B1824004639956E8C1EDAF31A8224191E8ABD645D2901F5B164B4B93F98039A6EAEC6088 , DSA.params_q = 0xE1FDFADD32F46B5035EEB3DB81F9974FBCA69BE2223E62FCA8C77989B2AACDF7 } arbitraryNamedEC :: Gen (PubKeyEC, PrivKeyEC) arbitraryNamedEC = do name <- arbitraryCurveName let curve = ECC.getCurveByName name pair <- ECC.generate curve let d = ECDSA.private_d (snd pair) priv = PrivKeyEC_Named { privkeyEC_name = name, privkeyEC_priv = d } q = ECDSA.public_q (fst pair) pt = getSerializedPoint curve q pub = PubKeyEC_Named { pubkeyEC_name = name, pubkeyEC_pub = pt } return (pub, priv) arbitraryExplicitPrimeCurve :: Gen (PubKeyEC, PrivKeyEC) arbitraryExplicitPrimeCurve = do curve <- arbitraryPrimeCurve pair <- ECC.generate curve let cc = ECC.common_curve curve c = fp curve gen = getSerializedPoint curve (ECC.ecc_g cc) d = ECDSA.private_d (snd pair) priv = PrivKeyEC_Prime { privkeyEC_priv = d , privkeyEC_a = ECC.ecc_a cc , privkeyEC_b = ECC.ecc_b cc , privkeyEC_prime = ECC.ecc_p c , privkeyEC_generator = gen , privkeyEC_order = ECC.ecc_n cc , privkeyEC_cofactor = ECC.ecc_h cc , privkeyEC_seed = 0 } q = ECDSA.public_q (fst pair) pt = getSerializedPoint curve q pub = PubKeyEC_Prime { pubkeyEC_pub = pt , pubkeyEC_a = ECC.ecc_a cc , pubkeyEC_b = ECC.ecc_b cc , pubkeyEC_prime = ECC.ecc_p c , pubkeyEC_generator = gen , pubkeyEC_order = ECC.ecc_n cc , pubkeyEC_cofactor = ECC.ecc_h cc , pubkeyEC_seed = 0 } return (pub, priv) where fp (ECC.CurveFP c) = c fp _ = error "arbitraryExplicitPrimeCurve: assumption failed" arbitraryCurveName :: Gen ECC.CurveName arbitraryCurveName = elements allCurveNames allCurveNames :: [ECC.CurveName] allCurveNames = [ ECC.SEC_p112r1 , ECC.SEC_p112r2 , ECC.SEC_p128r1 , ECC.SEC_p128r2 , ECC.SEC_p160k1 , ECC.SEC_p160r1 , ECC.SEC_p160r2 , ECC.SEC_p192k1 , ECC.SEC_p192r1 , ECC.SEC_p224k1 , ECC.SEC_p224r1 , ECC.SEC_p256k1 , ECC.SEC_p256r1 , ECC.SEC_p384r1 , ECC.SEC_p521r1 , ECC.SEC_t113r1 , ECC.SEC_t113r2 , ECC.SEC_t131r1 , ECC.SEC_t131r2 , ECC.SEC_t163k1 , ECC.SEC_t163r1 , ECC.SEC_t163r2 , ECC.SEC_t193r1 , ECC.SEC_t193r2 , ECC.SEC_t233k1 , ECC.SEC_t233r1 , ECC.SEC_t239k1 , ECC.SEC_t283k1 , ECC.SEC_t283r1 , ECC.SEC_t409k1 , ECC.SEC_t409r1 , ECC.SEC_t571k1 , ECC.SEC_t571r1 ] primeCurves :: [ECC.Curve] primeCurves = filter isPrimeCurve $ map ECC.getCurveByName allCurveNames where isPrimeCurve (ECC.CurveFP _) = True isPrimeCurve _ = False arbitraryPrimeCurve :: Gen ECC.Curve arbitraryPrimeCurve = elements primeCurves getSerializedPoint :: ECC.Curve -> ECC.Point -> SerializedPoint getSerializedPoint curve pt = SerializedPoint (serializePoint pt) where bs = i2ospOf_ (curveSizeBytes curve) serializePoint ECC.PointO = B.singleton 0 serializePoint (ECC.Point x y) = B.cons 4 (B.append (bs x) (bs y)) curveSizeBytes :: ECC.Curve -> Int curveSizeBytes curve = (ECC.curveSizeBits curve + 7) `div` 8 arbitraryX25519 :: Gen (X25519.PublicKey, X25519.SecretKey) arbitraryX25519 = do priv <- X25519.generateSecretKey return (X25519.toPublic priv, priv) arbitraryX448 :: Gen (X448.PublicKey, X448.SecretKey) arbitraryX448 = do priv <- X448.generateSecretKey return (X448.toPublic priv, priv) arbitraryEd25519 :: Gen (Ed25519.PublicKey, Ed25519.SecretKey) arbitraryEd25519 = do priv <- Ed25519.generateSecretKey return (Ed25519.toPublic priv, priv) arbitraryEd448 :: Gen (Ed448.PublicKey, Ed448.SecretKey) arbitraryEd448 = do priv <- Ed448.generateSecretKey return (Ed448.toPublic priv, priv) instance Arbitrary SignatureALG where arbitrary = elements [ SignatureALG HashSHA1 PubKeyALG_RSA , SignatureALG HashMD5 PubKeyALG_RSA , SignatureALG HashMD2 PubKeyALG_RSA , SignatureALG HashSHA256 PubKeyALG_RSA , SignatureALG HashSHA384 PubKeyALG_RSA , SignatureALG HashSHA512 PubKeyALG_RSA , SignatureALG HashSHA224 PubKeyALG_RSA , SignatureALG HashSHA1 PubKeyALG_DSA , SignatureALG HashSHA224 PubKeyALG_DSA , SignatureALG HashSHA256 PubKeyALG_DSA , SignatureALG HashSHA224 PubKeyALG_EC , SignatureALG HashSHA256 PubKeyALG_EC , SignatureALG HashSHA384 PubKeyALG_EC , SignatureALG HashSHA512 PubKeyALG_EC , SignatureALG_IntrinsicHash PubKeyALG_Ed25519 , SignatureALG_IntrinsicHash PubKeyALG_Ed448 ] instance Arbitrary DateTime where arbitrary = let arbitraryElapsed = Elapsed . Seconds <$> choose (1, 100000000) in timeConvert <$> arbitraryElapsed arbitraryCertificateWithDNs :: PubKey -> DistinguishedName -- issuer -> DistinguishedName -- subject -> Gen Certificate arbitraryCertificateWithDNs pubKey issuerDN subjectDN = Certificate <$> pure 2 <*> arbitrary <*> arbitrary <*> pure issuerDN <*> arbitrary <*> pure subjectDN <*> pure pubKey <*> pure (Extensions Nothing) arbitraryCertificate :: PubKey -> Gen Certificate arbitraryCertificate pubKey = do issuerDN <- arbitraryDN subjectDN <- arbitraryDN arbitraryCertificateWithDNs pubKey issuerDN subjectDN instance Arbitrary Certificate where arbitrary = arbitrary >>= arbitraryCertificate instance Arbitrary RevokedCertificate where arbitrary = RevokedCertificate <$> arbitrary <*> arbitrary <*> pure (Extensions Nothing) instance Arbitrary CRL where arbitrary = CRL <$> pure 1 <*> arbitrary <*> arbitraryDN <*> arbitrary <*> arbitrary <*> arbitrary <*> pure (Extensions Nothing) arbitrarySignedExact :: (Show a, Eq a, ASN1Object a) => a -> Gen (SignedExact a) arbitrarySignedExact = objectToSignedExactF doSign where doSign _ = (,) <$> arbitrarySig <*> arbitrary arbitrarySig = B.pack <$> vector 16 arbitrarySignedCertificate :: PubKey -> Gen SignedCertificate arbitrarySignedCertificate pubKey = arbitraryCertificate pubKey >>= arbitrarySignedExact instance (Show a, Eq a, ASN1Object a, Arbitrary a) => Arbitrary (SignedExact a) where arbitrary = arbitrary >>= arbitrarySignedExact arbitraryCertificateChain :: PubKey -> Gen CertificateChain arbitraryCertificateChain pubKey = do rootDN <- arbitraryDN otherDNs <- nub <$> resize 3 (listOf (arbitraryDN `suchThat` (/= rootDN))) if null otherDNs then do root <- generateCert pubKey (rootDN, rootDN) return $ CertificateChain [root] else do rootKey <- arbitrary root <- generateCert rootKey (rootDN, rootDN) let dnPairs = zip (rootDN : otherDNs) otherDNs -- (issuer, subject) keys <- vectorOf (length otherDNs - 1) arbitrary certs <- zipWithM generateCert (keys ++ [pubKey]) dnPairs return $ CertificateChain $ reverse (root : certs) where generateCert key (issuerDN, subjectDN) = arbitraryCertificateWithDNs key issuerDN subjectDN >>= arbitrarySignedExact shuffleCertificateChain :: CertificateChain -> Gen CertificateChain shuffleCertificateChain (CertificateChain []) = error "empty certificate chain" shuffleCertificateChain (CertificateChain (leaf : auths)) = CertificateChain . (leaf :) <$> shuffle auths cryptostore-0.3.1.0/tests/X509/Tests.hs0000644000000000000000000000542207346545000015707 0ustar0000000000000000-- | X.509 tests. module X509.Tests (x509Tests) where import qualified Data.ByteString as B import Data.X509 import Crypto.Store.X509 import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.QuickCheck import Util import X509.Instances () keyTests :: TestName -> String -> Int -> TestTree keyTests name prefix count = testGroup name [ testCase "read public key" $ do keys <- readPubKeyFile fKey length keys @?= count , testCase "read certificate" $ do cert <- readSignedObject fCert :: IO [SignedCertificate] length cert @?= 1 , testCase "same key" $ do cert <- readSignedObject fCert :: IO [SignedCertificate] keys <- readPubKeyFile fKey assertBool "keys differ" $ let [c] = cert key = certPubKey (signedObject (getSigned c)) in all (== key) keys , testCase "write certificate" $ do bs <- B.readFile fCert let objs = readSignedObjectFromMemory bs :: [SignedCertificate] writeSignedObjectToMemory objs @?= bs , testCase "write public key" $ do bs <- B.readFile fKey let (key : _) = readPubKeyFileFromMemory bs assertBool "first key differs" $ writePubKeyFileToMemory [key] `B.isPrefixOf` bs ] where fCert = testFile (prefix ++ "-self-signed-cert.pem") fKey = testFile (prefix ++ "-public.pem") propertyTests :: TestTree propertyTests = localOption (QuickCheckMaxSize 5) $ testGroup "properties" [ testProperty "marshalling public keys" $ \keys -> keys === readPubKeyFileFromMemory (writePubKeyFileToMemory keys) , testProperty "marshalling certificates" $ \objs -> asCerts objs === writeReadObjs objs , testProperty "marshalling CRLs" $ \objs -> asCRLs objs === writeReadObjs objs ] where writeReadObjs :: SignedObject a => [SignedExact a] -> [SignedExact a] writeReadObjs = readSignedObjectFromMemory . writeSignedObjectToMemory asCerts = id :: [SignedCertificate] -> [SignedCertificate] asCRLs = id :: [SignedCRL] -> [SignedCRL] x509Tests :: TestTree x509Tests = testGroup "X509" [ keyTests "RSA" "rsa" 2 , keyTests "DSA" "dsa" 1 , keyTests "EC (named curve)" "ecdsa-p256" 1 -- , keyTests "EC (explicit prime curve)" "ecdsa-epc" 1 , keyTests "X25519" "x25519" 1 , keyTests "X448" "x448" 1 , keyTests "Ed25519" "ed25519" 1 , keyTests "Ed448" "ed448" 1 , propertyTests ] cryptostore-0.3.1.0/tests/files/0000755000000000000000000000000007346545000014703 5ustar0000000000000000cryptostore-0.3.1.0/tests/files/cms-auth-enveloped-kari-data.pem0000644000000000000000000001551307346545000022746 0ustar0000000000000000-----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGBwaGBvgIBA6BRoU8wCQYHKoZIzj0CAQNC AARLFBy9/eI4x8mR5wpZ774i/LeS8/FzuGegHdAo19bTdzUlv9kd69/0GzRF5ntH 27ueue5YBRmFOKSRnLiU2mq3MBgGCSuBBRCGSD8AAjALBglghkgBZQMEAQUwTDBK MC4wITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4A BBjXV1HlxJT+Z8o6n5HC4RNRe7j4sP48HpIwgAYJKoZIhvcNAQcBMB4GCWCGSAFl AwQBBjARBAypQxH70WFEpg8UWToCARCggAQO6V6dHzqpE6FXmRa7arIAAAAABBCl bbL/+bic+x2r79kZpLsSAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGBvqGBuwIBA6BRoU8wCQYHKoZIzj0CAQNC AASJYlJVbYCr1BOjZpCH5hjLV/2X23Xc0Z5eTI8FBqUXlYHH7d1S/jEGJDfCcvIx TV9swOSRFK92I9kSVd9XCN1eMBUGBiuBBAELADALBglghkgBZQMEAQUwTDBKMC4w ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4ABBgE Xp5V6/AbK9bFcwjRJ3fm20YWgQ2nBowwgAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQB BjARBAyFVoCkD/eJA9YqjI8CARCggAQOpQwAlrBtnityfLYqU2sAAAAABBDLM+53 Uk0Pn3Y7MZ+Mbn5eAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGBvqGBuwIBA6BRoU8wCQYHKoZIzj0CAQNC AASufl1PpqFUZDuTCXzKMaGerIO5843VUFSwBudjyvovjAHTcGwPJjvS+3EH4NEn 7o/W7P09hwTSZ/rsBbBJPu+QMBUGBiuBBAELATALBglghkgBZQMEAQUwTDBKMC4w ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4ABBie ykbOXeqVMmbDWw3Ehn/QTjMlNs1uCL4wgAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQB BjARBAxEc1PrzckaDXBkWjgCARCggAQOuyUnmFAV/xahqSadwG8AAAAABBBi++VJ NnU5UVDQ6q1zMRqfAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGBvqGBuwIBA6BRoU8wCQYHKoZIzj0CAQNC AATX8MYoU25w7qYU/CFl+JZdFQ1ePZP2yL+FUJeV76Etegb+eeTl0dG70MIpVP3c uABRryMgV3jAniwgDnLDcLCrMBUGBiuBBAELAjALBglghkgBZQMEAQUwTDBKMC4w ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4ABBhe 7wfppjJXy8UnxeR3KYGpjqhss/Vdb/4wgAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQB BjARBAyS8HZXcf5oDpq7XSYCARCggAQON5pXJ2YeE3u0Tu/JggsAAAAABBCDUZMb f9iObxa0nURyr2uNAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGBvqGBuwIBA6BRoU8wCQYHKoZIzj0CAQNC AAQ50l98gMx9YTsLyif3Aj6ypa+8auXV415+hA7bgI5aXrY+20tvGbUheWAdCUM/ DVLWcYhsWEwTEmL6Z5dMrQDCMBUGBiuBBAELAzALBglghkgBZQMEAQUwTDBKMC4w ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4ABBjI vXtw3gmmAn/yORO1a/NTTGqgmpOQq+swgAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQB BjARBAw/RTlPW3aoaAWpb4ACARCggAQO7kbgLubm2M+hoanfMdkAAAAABBAeQyvO tOT7PWNiqKaFTu9HAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGByaGBxgIBA6BRoU8wCQYHKoZIzj0CAQNC AAS/VBtw4zaTtkAb45PJ8cuAYshMXy/F1lKa3ZA4E6u3np+dfQ+kBT5VrxpegvFj Q/NdOxV4CTatDnNo8iH5h2d4MBgGCSuBBRCGSD8AAjALBglghkgBZQMEARkwVDBS MC4wITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4A BCB5X3DkEOElcCL2KEOiVJKcQpTqQWynlMyWeLe805y4YDCABgkqhkiG9w0BBwEw HgYJYIZIAWUDBAEaMBEEDPX7veh9yNKL511dCwIBEKCABA5/r2CzelEUDNFaJtk8 jQAAAAAEEOWvi2b2dguSk94AjnrFBSAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGBxqGBwwIBA6BRoU8wCQYHKoZIzj0CAQNC AAQA3+RNupbspd7hUIQg7vXkrzB01ofr/7s7WuASl0OdzgJ3mBt3a5xtW7IqTE+B 3Vw9J4mkAa9PLi3Iq9SEkZ5aMBUGBiuBBAELADALBglghkgBZQMEARkwVDBSMC4w ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4ABCDl 4XWpLmEPvdcqjhnf7xp8sDnDIVZ/eKXxzQ8YU7+avTCABgkqhkiG9w0BBwEwHgYJ YIZIAWUDBAEaMBEEDIKxljwkGp/uATZNuQIBEKCABA4JT8FfOkbtIUd9TPivOgAA AAAEEOTGxEy5JLrS0+nAg5HtSDEAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGBxqGBwwIBA6BRoU8wCQYHKoZIzj0CAQNC AARJpGAQMIpwZgHJpg2o1wmxGYoNcgtHEhedsOFLpQdou3G69y0eDgX7nB0tvRt7 oYZEbgLPk7f4AECFVWSxnby9MBUGBiuBBAELATALBglghkgBZQMEARkwVDBSMC4w ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4ABCD0 HNfAnxgaNrlr1hC6M6O34Vyq1ZZ7MAInchQ6QjW8/TCABgkqhkiG9w0BBwEwHgYJ YIZIAWUDBAEaMBEEDDj5sfWnIjCmTf1y9wIBEKCABA5k60PO+CFkHN/evabZmwAA AAAEEJCwak43a0Ga4riBRKY9CNsAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGBxqGBwwIBA6BRoU8wCQYHKoZIzj0CAQNC AAQj7fNzGeluKhvEL1t7QM9hnKiNItc4UEkHFzz3WJqepjx14l057XMAQoiyut9G +W+Ddqx+ozVQOxu1RO5BHEY/MBUGBiuBBAELAjALBglghkgBZQMEARkwVDBSMC4w ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4ABCBO XDmcoiudX6iCODyKyf+kj4ahTrVfH/kWYbocdvgrCzCABgkqhkiG9w0BBwEwHgYJ YIZIAWUDBAEaMBEEDL9ZV62lILi166Kr/wIBEKCABA7ayB6TLDk4NOQYpj6kvAAA AAAEEOiMHVSsVG7a7WcQp7DQmcgAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGBxqGBwwIBA6BRoU8wCQYHKoZIzj0CAQNC AAQnuS9ANZe6b7GWHi5qQQozrTubhuGToeFZAdQtiz95z5OrgWkmiX6ERkwaN1xB 06M7crT9vuG0pX4GoboI4p4nMBUGBiuBBAELAzALBglghkgBZQMEARkwVDBSMC4w ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4ABCA0 PNagjdeo/KS1G+Y/lqmh3Rvz0T4rIVYChhNdvZWxbzCABgkqhkiG9w0BBwEwHgYJ YIZIAWUDBAEaMBEEDInQ2rexl6MGVX7tsgIBEKCABA4yHXaDnnVGt09Ctn67lgAA AAAEEGUG2rPiuRtGhTarSuS64uQAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGB0aGBzgIBA6BRoU8wCQYHKoZIzj0CAQNC AARnR8BsuxfZyGI8EufwUGDG+XuPF/1XzhhogH1DpHQy9XON4DUyLvlkWP+voIwE uMApKF5ESL1IL8T6UnzoN55AMBgGCSuBBRCGSD8AAjALBglghkgBZQMEAS0wXDBa MC4wITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4A BCgetPskb6M89OJ/Q6C9WwJYZrbT9Upvvktf8EHiRPWPri4BWOc8hcn8MIAGCSqG SIb3DQEHATAeBglghkgBZQMEAS4wEQQMxjZlfwz1CXn6KQBeAgEQoIAEDq6U8zcr EcjV5QDm7KA0AAAAAAQQruuKaBMv3S7igAIPPQp5jwAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGBzqGBywIBA6BRoU8wCQYHKoZIzj0CAQNC AAQEtpMiE4i41ln4lBfxorG/Mz7ENYFhI3FFjzvphl+/n58x3AhZHsKdJQfiBgwQ NbRjVoSg6gqA1NgwlJfMdC5yMBUGBiuBBAELADALBglghkgBZQMEAS0wXDBaMC4w ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4ABCie fGtGheoPu9MlqzfxIkshaxv58mwcvnrO7Zjztbr/Y8iu+mQc6UVHMIAGCSqGSIb3 DQEHATAeBglghkgBZQMEAS4wEQQMRnxKZZFpluuCvzMUAgEQoIAEDgbHkpLneCpj J3kFkjUHAAAAAAQQiRN5pWovrd3DmXkxUfScsgAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGBzqGBywIBA6BRoU8wCQYHKoZIzj0CAQNC AARK9880f2VoFvmoN8xEHSn68EplcakaakOQgEqIJqYhQtk+jzWcONqFH13Tydf0 twC6i18Ip33oM4qNO5baDw+/MBUGBiuBBAELATALBglghkgBZQMEAS0wXDBaMC4w ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4ABCgU SlctsM4RmvAM189y5SF74X37M5v7amwj7Q2NxcwdqYq/T2Spvjh0MIAGCSqGSIb3 DQEHATAeBglghkgBZQMEAS4wEQQMMaNatdENR6VvbGKnAgEQoIAEDmuLMPNqEAZV 4G5072SbAAAAAAQQZil2/HiSIzjZEhj2xQjSCgAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGBzqGBywIBA6BRoU8wCQYHKoZIzj0CAQNC AASbBeETneRZ79Q5cGBu17gZFZM++ZWzsMvcmx6Z1gYztIKYWtndW+INxVvrln4D Of8maq6/IfumffkvZpfqBnKPMBUGBiuBBAELAjALBglghkgBZQMEAS0wXDBaMC4w ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4ABCho nDmmA4NRBHpBGIGI0SwDPTw6CO1Adwjz6uhtcKd99duC7o50kQZgMIAGCSqGSIb3 DQEHATAeBglghkgBZQMEAS4wEQQMJjonwKRKw6ThEDRlAgEQoIAEDs/bEIQQtKP9 EZOmpMsFAAAAAAQQxCZqg6Ec63VcVAJgsVofaAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGBzqGBywIBA6BRoU8wCQYHKoZIzj0CAQNC AAT0yC7d8EmBaHZecCKf8SOdDqm/o2CJteAk7ICcqbMjBhJc93ckpyE4o1Z/gB1Y 1zwgerWFeaZXfObcRxh2CxZGMBUGBiuBBAELAzALBglghkgBZQMEAS0wXDBaMC4w ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6ZvHS4D4ABChH RQJ5OmptF0ap3vq7lknTscDMjwld7FhuDlxurwXb61f/Ubv8RsGAMIAGCSqGSIb3 DQEHATAeBglghkgBZQMEAS4wEQQMEy1/SaOMEMJCYYB/AgEQoIAEDiDXAvTAGTTP 4RN37jTOAAAAAAQQEJHRPVxSAJBdZ//YdeM1LQAAAAAAAA== -----END CMS----- cryptostore-0.3.1.0/tests/files/cms-auth-enveloped-kekri-data.pem0000644000000000000000000000146207346545000023123 0ustar0000000000000000-----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADExoi8CAQQwAwQBMDALBglghkgBZQMEAQUE GKdm3FAAb+cJzRlmBNrIxZJR/lO7Hl9I9TCABgkqhkiG9w0BBwEwHgYJYIZIAWUD BAEGMBEEDBy96EqGGAX5GsRkvgIBEKCABA4/POyH35OvITLf81WHwQAAAAAEEKuM jJcreoQAUFYD+Y3HRCkAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADE5ojcCAQQwAwQBMDALBglghkgBZQMEARkE IKEh8evpAq55aqYZa5EcwTXkGGFsx9Xljf5YWzLOVzPJMIAGCSqGSIb3DQEHATAe BglghkgBZQMEARowEQQM2qmxxSb4nQshdsBZAgEQoIAEDj/eccFTdRRtFS59ge54 AAAAAAQQlv+TpgF6XXZsjdVzg5uV7wAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADFBoj8CAQQwAwQBMDALBglghkgBZQMEAS0E KCp5RYkgCzU42HF7XXOaFQOEsk9bUFFxgV9NDlyVAo+2RrIPgVXXkMEwgAYJKoZI hvcNAQcBMB4GCWCGSAFlAwQBLjARBAx/18iNa9gajkGa3qYCARCggAQOZ0Hn+848 qApi912KpsQAAAAABBBpz1K5ojGHJznVxTUAWfD9AAAAAAAA -----END CMS----- cryptostore-0.3.1.0/tests/files/cms-auth-enveloped-ktri-data.pem0000644000000000000000000000537607346545000022777 0ustar0000000000000000-----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGByDCBxQIBADAuMCExHzAdBgkqhkiG9w0B CQEWEHRlc3RAZXhhbXBsZS5jb20CCQD3DetZLCk3mzANBgkqhkiG9w0BAQEFAASB gA/maH0B5EK0DLU5rfbTGet4uBklSW9TkEfAskjNJ6C1KfePfy20oNfnsKMS5Mp1 q/3Bz77LgH8+TWBZ5LKbgOT6AiMpWlUuUqzuchxmC9nx5P/ew0WJPQME5igMaV0z 1rstr7dMZtIMa8aTQMzJ+LgguRNOYBuBLvB1w1vaxrc+MIAGCSqGSIb3DQEHATAe BglghkgBZQMEAQYwEQQMlYZ0LFrSPPCSCobkAgEQoIAEDpNaDCywbuuvs15vS6S7 AAAAAAQQGLodMaocucmqaveg0fT5xQAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGByDCBxQIBADAuMCExHzAdBgkqhkiG9w0B CQEWEHRlc3RAZXhhbXBsZS5jb20CCQD3DetZLCk3mzANBgkqhkiG9w0BAQcwAASB gFrnvmHQe5ja0uvf6ni5ea0Jkss11cJ62lpyq41AYD52AwaoCC+FFdykgQBxgpO+ 1Byj0cUzzpxFoV354aZg2xUKu7RrN2ogUlei8TdEctfe5imOHPaD+W94xSipT46+ VEXs+k7LsrJMtqBHmNvSZGIz/r6PpJMB0+Q5m1dqJQ8gMIAGCSqGSIb3DQEHATAe BglghkgBZQMEAQYwEQQM44g5NAyvNtg1f7IhAgEQoIAEDvxH9L2wJAxh02F+yTgv AAAAAAQQa+rmrc/5NDP5/kB9FDvnkwAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGByDCBxQIBADAuMCExHzAdBgkqhkiG9w0B CQEWEHRlc3RAZXhhbXBsZS5jb20CCQD3DetZLCk3mzANBgkqhkiG9w0BAQEFAASB gBiKzwAxQcgNfC5I/jsSWn559jU2f/ndZE4he3ojQua1HHrVVJUFVbwUC7bYs3Vf nHjo5AHi0i408asv4l2BgH3JWVkhnaUtHEajnipWkBEF2Bipb5u2i5NpeCMATdnX vUuUL6UAarWQttcWu+/J+73ZtV0ecrd8ybTIlcOx0QrtMIAGCSqGSIb3DQEHATAe BglghkgBZQMEARowEQQM+TWtLNHBl3EU+JUdAgEQoIAEDtXaoIj5rEJLWljHXk0e AAAAAAQQjXRzifuEu8tEWisIQkPk6QAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGByDCBxQIBADAuMCExHzAdBgkqhkiG9w0B CQEWEHRlc3RAZXhhbXBsZS5jb20CCQD3DetZLCk3mzANBgkqhkiG9w0BAQcwAASB gDBMbmVbY3ghH4Pc9N/kDCoYVb6Mp93oUOjLhVpx71Bqxv8xoWXzT4NV2Z3ssE/F k3RG1Y7LMYfv2I0QVZetuWJIehRBqouY/uW4RM7WWemuLT46M7Qszoi3vMnZ7Tuj 8tbxQUeie4dBO0+MMluNYj4hc/gzaCxsy0nqISG6ERGFMIAGCSqGSIb3DQEHATAe BglghkgBZQMEARowEQQM8zQfTdCgHG5KfkebAgEQoIAEDoJVmSUFhPA5dLsML5F9 AAAAAAQQE3SXLSthb+rnxYrwohzIvQAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGByDCBxQIBADAuMCExHzAdBgkqhkiG9w0B CQEWEHRlc3RAZXhhbXBsZS5jb20CCQD3DetZLCk3mzANBgkqhkiG9w0BAQEFAASB gIIv6EsKwGSUU0M4EHjI8mgYF1mm32nPIHf4xwYuKcgE9Klu8/Dob2k+Q5705aAc 0mQvGiA8iaguiveGzvXegyuv/LVjl7bz1aTYkXwo22+5J3YstFJPrum+S1FbBdvI cKPzkUjaJDus1R0j36Zej2wYnTUJNSo4SE1lolcyAUj/MIAGCSqGSIb3DQEHATAe BglghkgBZQMEAS4wEQQMtwUSL7+j+tyKBlp3AgEQoIAEDp3QpaI+/etoalZIMW+G AAAAAAQQ99WOo5xvNPX1CYu/2b9LoQAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCyqGSIb3DQEJEAEXoIAwgAIBADGByDCBxQIBADAuMCExHzAdBgkqhkiG9w0B CQEWEHRlc3RAZXhhbXBsZS5jb20CCQD3DetZLCk3mzANBgkqhkiG9w0BAQcwAASB gC5UFYfqMeb1SoHKS3G2dr+ofYwU4+JzVrqCJnE6WKSQI3a50MN63TTpjuiOxnWU TCzo7QUIFCUms+NIFNR1FGmV58SycQqs/9gQcR0Xp9mnL0LkGte6pIIEnro+dHES aY+6eRViwFOZ6GO0qOODUgLHfYdotcqnuKEs8oV3IJb1MIAGCSqGSIb3DQEHATAe BglghkgBZQMEAS4wEQQMnJh28SAHjbT8F2U3AgEQoIAEDkcXXJq6tkKrY3tI5ecW AAAAAAQQK2+jlHbQwEjmeP0vQxBRZwAAAAAAAA== -----END CMS----- cryptostore-0.3.1.0/tests/files/cms-data.pem0000644000000000000000000000012307346545000017073 0ustar0000000000000000-----BEGIN CMS----- MB0GCSqGSIb3DQEHAaAQBA5oZWxsbywgd29ybGQNCg== -----END CMS----- cryptostore-0.3.1.0/tests/files/cms-digested-data.pem0000644000000000000000000000203707346545000020667 0ustar0000000000000000-----BEGIN CMS----- MFEGCSqGSIb3DQEHBaBEMEICAQAwDAYIKoZIhvcNAgUFADAdBgkqhkiG9w0BBwGg EAQOaGVsbG8sIHdvcmxkDQoEEM1RYEXDSwgRKZGd+Ja3VVo= -----END CMS----- -----BEGIN CMS----- MFAGCSqGSIb3DQEHBaBDMEECAQAwBwYFKw4DAhowHQYJKoZIhvcNAQcBoBAEDmhl bGxvLCB3b3JsZA0KBBSCJcpSBohk9ZFjXX73CaruHbNZqA== -----END CMS----- -----BEGIN CMS----- MFwGCSqGSIb3DQEHBaBPME0CAQAwCwYJYIZIAWUDBAIEMB0GCSqGSIb3DQEHAaAQ BA5oZWxsbywgd29ybGQNCgQczcRQGqOTlmA3SbLea8IWbnraq6CgYvJB35ds7A== -----END CMS----- -----BEGIN CMS----- MGAGCSqGSIb3DQEHBaBTMFECAQAwCwYJYIZIAWUDBAIBMB0GCSqGSIb3DQEHAaAQ BA5oZWxsbywgd29ybGQNCgQgu747Zx6FPf4woOYFlDZvJPAvMeok/0ZRdD/WDHPN aCI= -----END CMS----- -----BEGIN CMS----- MHAGCSqGSIb3DQEHBaBjMGECAQAwCwYJYIZIAWUDBAICMB0GCSqGSIb3DQEHAaAQ BA5oZWxsbywgd29ybGQNCgQwppJgPaHRdFOAXmaxqE4LqWf8xnTAsB2M/HiQTA/2 QQDpK7cvaFmjVu6jb8iCj5RL -----END CMS----- -----BEGIN CMS----- MIGABgkqhkiG9w0BBwWgczBxAgEAMAsGCWCGSAFlAwQCAzAdBgkqhkiG9w0BBwGg EAQOaGVsbG8sIHdvcmxkDQoEQNmRYGENk6X3fR9Sk9k++QSKUPYBvF+nGKHL4FXN QVoNz4kKv9BI4MPnsV77ikuw7kWGR3OFLWO8waCyFK+EEu0= -----END CMS----- cryptostore-0.3.1.0/tests/files/cms-encrypted-data.pem0000644000000000000000000000472007346545000021075 0ustar0000000000000000-----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMBEGBSsOAwIHBAikeD2B 358Jh6CABAjJSfpa1LuLyAQIY6cX6W8/IhwAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMBQGCCqGSIb3DQMHBAiC 6+NMJ44OmqCABAjW9hA48kkK3AQIh+a+VHqpvWMAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBAgQQ mkkKJDu2aiEgb0/ZxJBsYKCABBDcIZ09lh+9CsLaYdR1SgDOAAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBFgQQ j6MESspPo2oHNS89EDG1aKCABBATA2wR43qFEySZz42vGzGKAAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQ UVdEll0/Q4TaK20aQF9g2qCABBDEiZdmwk+evavQgmw1sComAAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMBUGCSqGSIb2fQdCCgQI GRIlaIuvmQ+ggAQILWj2kKDN1s0ECEiJbc0I7i2cAAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMBUGCSqGSIb2fQdCCgQI WDzAE/e9EsSggAQILkJl9q9FijEECNIDSgZF99sjAAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMB8GCyqDCIyaSz0BAQEC BBA2iD8nnUhmlqyjEW24xUTFoIAEEDgF21lihlEHVa1D4g17tDYAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMBoGCCqGSIb3DQMCMA4C AgCgBAjrdywymrZ6FKCABAj2In9qh8hjGAQI6wNZVOTYKTkAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMBkGCCqGSIb3DQMCMA0C AXgECFYB6AfzFjbOoIAECBJ3vXMNAn34BAjOBiCsA8vj7AAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMBkGCCqGSIb3DQMCMA0C AToECFxl2R8EmepkoIAECFnHCd1/a+BdBAj2gVsc+lQZxAAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMAkGBSsOAwIGBACggAQI wVvzZIHhjREECBpzXeoXbghhAAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMA0GCWCGSAFlAwQBAQQA oIAEEPq7Jdg9K+WiMDzclI2E3ZUAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMA0GCWCGSAFlAwQBFQQA oIAEEF9g2Xr4VpbfRXzmI6Trt6EAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMA0GCWCGSAFlAwQBKQQA oIAEEB6dQRYioWisrBYHjAebWgwAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMAwGCAOiMQUDAQkBBACg gAQQ6RwXVWk9R1eE7Jk7CUyMRAAAAAAAAAAAAAA= -----END CMS----- cryptostore-0.3.1.0/tests/files/cms-enveloped-kari-data.pem0000644000000000000000000005574607346545000022023 0ustar0000000000000000-----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgdWhgdICAQOgUaFPMAkGByqGSM49AgEDQgAE Ed6o5AhsIHUjW+EUXgK6gcsSpY5/tAXgBs9j1h9bNhvBquwRih2dDUmJwJRsjNcU UvhBljKPEy2ib6WeQnEsojAcBgkrgQUQhkg/AAIwDwYLKoZIhvcNAQkQAwYFADBc MFowLjAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tAgkAl/pm8dLg PgAEKPMvSLFKDI5Pc2NAr0tt7Jrhi82TZo6auIhDBjV4R2PCVe+I680iwiowgAYJ KoZIhvcNAQcBMBQGCCqGSIb3DQMHBAi9UZzbbgEaHKCABAj/zb76X6Se/gQIrc14 qkjoFYMAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgdKhgc8CAQOgUaFPMAkGByqGSM49AgEDQgAE 2Y+zAHO5ulufpaH44mk3kGBgfd9vWzq5HkRae8dlaezpaSmc+oKtZlGZXDuC7bEP 5eluiynuYYfVVgxETZQ7TDAZBgYrgQQBCwAwDwYLKoZIhvcNAQkQAwYFADBcMFow LjAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tAgkAl/pm8dLgPgAE KB36kd95/gx1SjDa4+UL4qWXd1RDCqPFhcSLyCJyAIF19WkCc0U3o8QwgAYJKoZI hvcNAQcBMBQGCCqGSIb3DQMHBAh5J5a0tWhj+6CABAhq554Xa7EUdwQIgxGzaXwT nX4AAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgdKhgc8CAQOgUaFPMAkGByqGSM49AgEDQgAE XFCZOCO50366MGOprn5RzFqhDK/VHN4zCAripWsSE/MJafxfNd8ov7liRj5e/Rwp PtA5wysulypS8sL/8RlwUDAZBgYrgQQBCwEwDwYLKoZIhvcNAQkQAwYFADBcMFow LjAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tAgkAl/pm8dLgPgAE KEhcaAC5MPm8Xf5YX7kmTTSoO4tG0rRhYqYLwb0pQFVVQlCSbi2JfqMwgAYJKoZI hvcNAQcBMBQGCCqGSIb3DQMHBAhe7ZmMpONL5qCABAgcSGlAlLskmAQIZt9VALxf dRwAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgdKhgc8CAQOgUaFPMAkGByqGSM49AgEDQgAE YnNf8skxVk51tvLHYy3hELWfOug40zlob+10nWeYxOBRBBcNmzLiVJ4VcwEDAvQH gSG/ftWR/cu8d7npjh/fTDAZBgYrgQQBCwIwDwYLKoZIhvcNAQkQAwYFADBcMFow LjAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tAgkAl/pm8dLgPgAE KPB7npEdNX96iMm3saaTkmkYBLwX1IVEgZU2NHqMNm2wvnBpeBouzq0wgAYJKoZI hvcNAQcBMBQGCCqGSIb3DQMHBAivrGaWndwuIaCABAisrCnBVtd/0AQI/h/EdI4d JHEAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgdKhgc8CAQOgUaFPMAkGByqGSM49AgEDQgAE WdNVTNdYqeSR5NCdy0s10ipnhzuQEj3/BoGyL2FL8M3fCrQdP36qacziFOoDjbNZ 8so2s33aXcCglhZ9/AyULTAZBgYrgQQBCwMwDwYLKoZIhvcNAQkQAwYFADBcMFow LjAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tAgkAl/pm8dLgPgAE KJPYTTgAItxMFq0Hqx16UDgGM+ZpkCrPyQARYs3XBZcrzqyDzdQY+XUwgAYJKoZI hvcNAQcBMBQGCCqGSIb3DQMHBAidhr3XY7svRKCABAgE1skQLauNDQQIvbre4W/d nX8AAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcGhgb4CAQOgUaFPMAkGByqGSM49AgEDQgAE NkH2menyiIOiyJMAsSWmBPPU49NrakPUDywzNitZa0Yu00DOTvmggkQP1RR+QSrk JEbx6xaCYxFaJNF/2ZgLBDAYBgkrgQUQhkg/AAIwCwYJYIZIAWUDBAEFMEwwSjAu MCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQY z1bGx7ABf5OxxKDHaoBXkho4PL2+0S5QMIAGCSqGSIb3DQEHATAdBglghkgBZQME AQIEEMD/gqzuyP3V8zydroS0AwiggAQQ6yjZFdDXrEn69YEKqIoXywAAAAAAAAAA AAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE t6fN7Ia3+ySsvomfy1FsAklLIEERQTKoknia/cMMsks/N+G9nijba7W3La6vUGCt eAiaYLp3vd0oUmgDKTgawTAVBgYrgQQBCwAwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYH3BR OSPFufyVQePGfvngsDBMtp/FmgNxMIAGCSqGSIb3DQEHATAdBglghkgBZQMEAQIE ENhrWc7aJlKi6KxbEX8vb8iggAQQNauiYNoLDzYsWl8mIvfYHQAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE oIjIxcHzuen6Vrr5qU8Qnb3l1MbCs/F6JK0uSRDOhgDlcCxF3R3LkqQ/eyyM4AjE KLY6aei6j/F6hy5rSvLFoDAVBgYrgQQBCwEwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYxdAR oqPDS7zSUuZny4vrAUsqJt8jcR3MMIAGCSqGSIb3DQEHATAdBglghkgBZQMEAQIE EMuSG2Cb05eLWCdAGIu3BcmggAQQE7wDkRaV9w14sPR2iXsaMAAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE bXzt6x2ihVjuL4djVxsWWLt60vLl7bsHAx23Zf7UfSIYL6grI2V6iTtFEV4YppnT jHq07oU+wsasCYBnrhGrBTAVBgYrgQQBCwIwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYy7XB WFrsqm7Qs0Gi9jDwbceZQWZvOsH6MIAGCSqGSIb3DQEHATAdBglghkgBZQMEAQIE EHERwOSL8JBMOaPAKywIL9WggAQQQHRSxU2L/5pOk9k+1MChQgAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE 2pxcjKYQaCqYHJ7NrJkbTdutonvhJ1ZHlayPhTJecw0OtTK5fAx2rwwUsRQaMYeT BuWWGCEvkwQkbMIYWhrhUzAVBgYrgQQBCwMwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYa3Qe EwS1T2VRYvbOaN/tQRCwQfy+066gMIAGCSqGSIb3DQEHATAdBglghkgBZQMEAQIE EB4Es/GYPUJ2f3F6BZWL1caggAQQ/0qaUyUkb0cnu0mAzH/IzAAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcmhgcYCAQOgUaFPMAkGByqGSM49AgEDQgAE Ok8M+RlivdV5+eJMInGlk3bHDp+lCY75r3WG21etOh5zve1MjlxIWW14MZJt7k0E jCl1QbeyzX1EB+hZOvxTvzAYBgkrgQUQhkg/AAIwCwYJYIZIAWUDBAEZMFQwUjAu MCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQg TgAwCMxitIJmcLt07j37L1QzqlGlzSxGJM4Qk11iQ8IwgAYJKoZIhvcNAQcBMB0G CWCGSAFlAwQBFgQQg/zLqFBHcCRnkyr9u3F+kqCABBA68WRoFD0KTi05iwYtRoZ1 AAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcahgcMCAQOgUaFPMAkGByqGSM49AgEDQgAE w09hnWB1xWff+NM3YGEioZc9d0bZdLbsj5i5DGRqp7YGmucLntyjXYvSyyaoKZYI X3/mgwjkOlpeoPeaEUjngTAVBgYrgQQBCwAwCwYJYIZIAWUDBAEZMFQwUjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQg8WuO nYYrxosyAxA4FdwxBWuCCN4DWm7QW1v3ohgo7JswgAYJKoZIhvcNAQcBMB0GCWCG SAFlAwQBFgQQr2Lf2U4dBL5fMJ3yRiL7eKCABBBxV6zUhoCpDylAiZf7FtWRAAAA AAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcahgcMCAQOgUaFPMAkGByqGSM49AgEDQgAE RkIgB0n1JaTuswpI3CvbFo7HM9esPnajZpjVNEbkIWncwq203luV2poABI1yd3f0 8ID1LlhSgzVBh4jLIheAOzAVBgYrgQQBCwEwCwYJYIZIAWUDBAEZMFQwUjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQgHezE 008dCR0GpVxBjcHOLALlpcBiJYemn5/Gd0Q8hZIwgAYJKoZIhvcNAQcBMB0GCWCG SAFlAwQBFgQQwHGxX3MzxEAb7tF4q5aZZaCABBArUt/vthlUC+CiE5ZF5n17AAAA AAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcahgcMCAQOgUaFPMAkGByqGSM49AgEDQgAE TM9a8AkCWY+1PPUiv8YRTDP8CkM8TVguegkv37otYosgoLj5S0IJ5qLuVDmIsrEh JV/1M7k3jVghCh8Fk4N74zAVBgYrgQQBCwIwCwYJYIZIAWUDBAEZMFQwUjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQgTUP+ ohzITwtreuhRAYCS3xgKjC224WJWNWl71e12tdgwgAYJKoZIhvcNAQcBMB0GCWCG SAFlAwQBFgQQcToIk1W67hLKdYiS0Rv0sqCABBDS/GmIldQoA+y0dpNdb1NiAAAA AAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcahgcMCAQOgUaFPMAkGByqGSM49AgEDQgAE l87IK6nNVNDGFqQ7aEqqfIDhukqCFWubjY4V1Na8GIiaAZ9mv9Flk8bqqEaVI4Z3 eZiVZ70fYeeXDQK6IP/HSjAVBgYrgQQBCwMwCwYJYIZIAWUDBAEZMFQwUjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQgst2+ ObTvFwlaVdcaVUOGT5dNljVOgFss2P/7HdoxzxkwgAYJKoZIhvcNAQcBMB0GCWCG SAFlAwQBFgQQ/YZVdo7qn1Ur5IvS8krveaCABBCXs1En2ICNad4m9RUv95aYAAAA AAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgdGhgc4CAQOgUaFPMAkGByqGSM49AgEDQgAE CVsIWAAIOjLr6akT92E3GnGkuGu/uiV/O5CORs0gieMXoIg00XoVXFvF97w3lIR5 LSeReKZfeCeqg3sHQ5B0YTAYBgkrgQUQhkg/AAIwCwYJYIZIAWUDBAEtMFwwWjAu MCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQo aNVpE6iz37lKYrP5eFAktgCDq1874/V23eeiVLz8EeUIu4LLL+zkdzCABgkqhkiG 9w0BBwEwHQYJYIZIAWUDBAEqBBCldPVP1En+B7twjFmIf9gCoIAEEBQeL+Df7Z0V 01XPBAXNQAkAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgc6hgcsCAQOgUaFPMAkGByqGSM49AgEDQgAE 2acvj/2X41n/UnA+AbfP9FdqBsmPKhzSSJWoqjBc+LvvrEFyv/kvRzF5BVpU9lcq OoUA899tXIMMqHezDzN/wDAVBgYrgQQBCwAwCwYJYIZIAWUDBAEtMFwwWjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQoRj7S 0EOP5XoG8DQWywlF3Iys25+1UTQq4KZddk4EvvxuUZ5hbw40+TCABgkqhkiG9w0B BwEwHQYJYIZIAWUDBAEqBBDy3jMIbY+L6/nhjGQRmpBDoIAEEBSpJEtVjBwaeZuQ GPdO3B8AAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgc6hgcsCAQOgUaFPMAkGByqGSM49AgEDQgAE BherrKZIQMHjt/tf6gpZ0LI7MkBGoDMPFY9VvgrJ9yn8Fy4NAaXBLL3q2V+maZtY HjTVMq+nCTgNU6TRtk5eOzAVBgYrgQQBCwEwCwYJYIZIAWUDBAEtMFwwWjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQotN9/ b6c9aJnElELnDoL8Vl/bD+GbxARw9r61Mffaje2DwvMurVk9ljCABgkqhkiG9w0B BwEwHQYJYIZIAWUDBAEqBBBadkWusaPBLljDA2uaOJvioIAEEMK6XkBQQRUfjkzF zFyWDVsAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgc6hgcsCAQOgUaFPMAkGByqGSM49AgEDQgAE OCdlCnQEZi1ty887EKww+iZwZUjLZ3IdS+6AAnDLb4D/OpoRobmYD0TT1ihcCYdO Hfs2y7WUskWWEpItGdkpDzAVBgYrgQQBCwIwCwYJYIZIAWUDBAEtMFwwWjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQoRlHj cDX/7zCtOM+ZdjGFepFWH9bfrXopmSINNL9CCH/KHemYSr2ByDCABgkqhkiG9w0B BwEwHQYJYIZIAWUDBAEqBBBFdMNJ+RS/WQnalqWS0KG8oIAEEBvHcKhUPjh+JPcq Kr6LxYUAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgc6hgcsCAQOgUaFPMAkGByqGSM49AgEDQgAE tL64aZ6HovPynNbmtlIokrDIicvGdomhqjqG+Tv6Ji9Wcr/1PIH/KMjxxaIMV/Ou RHR31qHADGry+ZZ/mXizITAVBgYrgQQBCwMwCwYJYIZIAWUDBAEtMFwwWjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQomSyh 09xxkpMeODlDWDLi3jrq4NaVOeQVB/E7JnwN4MJuTHDu40fxDDCABgkqhkiG9w0B BwEwHQYJYIZIAWUDBAEqBBD+Ca0nBbH4qbQL+tgVIx8zoIAEEJ5SxJ+Aw8QtKUQG DGcE0CAAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcGhgb4CAQOgUaFPMAkGByqGSM49AgEDQgAE gZKsGO/M7D9GqyaISh/qOOYm3uM8GD/2u9E864FiDdAE+SHPOYG8xgx0kQxxTzfA 6EvnXbfhWOT4hmiEL++bTjAYBgkrgQUQhkg/AAIwCwYJYIZIAWUDBAEFMEwwSjAu MCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQY NYzMGrZJ76aNAOtU7dsLIJ0Itg5SbSI3MIAGCSqGSIb3DQEHATAVBgkqhkiG9n0H QgoECI7LjKaujpDRoIAECBjJbDivGx2IBAjiOnGDfU6u/gAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE IBqf10T8dNW1hxj9HMSoNIaaZtl8RPZfloQfgihKvYg9aXuE+Q5RdC4GV/f1pLxd JgESlcl/3mOBKohqAvMMmjAVBgYrgQQBCwAwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYNUnq GaHHtDTCdltY4G7FOyTM1oiWP9qoMIAGCSqGSIb3DQEHATAVBgkqhkiG9n0HQgoE CBjyxYOtxWvZoIAECLyMrarzIhWlBAh72cydBQhIyAAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE rP25FELCbEM5jBWeeU2rzq0sN3aYACNAznb2u9QA+8FYKUeifEPXN4FAmHZWO0BT Lb8XF9w84Ra0lA7INV1RmzAVBgYrgQQBCwEwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYXzBl /qAahtKaYTCUeb3AYTRyBGnk8RVNMIAGCSqGSIb3DQEHATAVBgkqhkiG9n0HQgoE CGEmLKtt35HqoIAECAKttXW1125kBAh2WTqti5Y+mAAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE rwn4M/Ame+7UEZmJk3NWyLzfnMvt8CyvRDk3/lILCKRGv8yFi+NMxY0Pnkl/w3lJ jmtBSTzyl0FH86yVujnbmTAVBgYrgQQBCwIwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQY4fPV R/Fa5/ielrY0nFK3UbU/+FwdKIsHMIAGCSqGSIb3DQEHATAVBgkqhkiG9n0HQgoE CA5LtVn2hR9FoIAECAUAcOqFIJEQBAhb3SxGXkA89wAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE vNqu+oATVqFdAiZIOmdcprvBVhSplrBCBvhPkP25O/Z9o+O9xsnpVZE2vAgftwSA KjPw8sqERpPiYUGOxLxdmjAVBgYrgQQBCwMwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYxYV9 jFhY6lIpkXN8AWQJQkNiTDXK9XWSMIAGCSqGSIb3DQEHATAVBgkqhkiG9n0HQgoE CP4ABapU/5IzoIAECLUree4PSI1DBAgyAi+gSInDhAAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcGhgb4CAQOgUaFPMAkGByqGSM49AgEDQgAE d4LCQ76At7ug9FqIfvw+Kg2IzG3K8jYD53kqVR0awkV3eRIV/CY+nkyI/x68Gc2y UOBeE3BykJ9yaARY9ZuQzzAYBgkrgQUQhkg/AAIwCwYJYIZIAWUDBAEFMEwwSjAu MCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQY AELGlK0LQ4aMsSoIKeMfZcxcGnqwzLXpMIAGCSqGSIb3DQEHATAfBgsqgwiMmks9 AQEBAgQQs6uUmpJ+F2+POVFx59Gbz6CABBASwae11oKDmhaMFreD14ehAAAAAAAA AAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE 6r53ZnLlnO/GpWmxUOvb6FMAyVL99UzfwaPd6jGIkV4/D3/NJLoUAEPjwJwUey6C NIYyCTlMFertMzhffcgBMzAVBgYrgQQBCwAwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYsSSC Png7v6TOhSlBD5yjAJLv/sLQTMLkMIAGCSqGSIb3DQEHATAfBgsqgwiMmks9AQEB AgQQ6U90bpZgD/3RS5cOJ1YcNqCABBCFcGfBZv8eoqkxM5j3D6zVAAAAAAAAAAAA AA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE Cce5H6wStNqCrn17cOPxAP41QTpUufb5aC9/sWUDkDNgpmm4SNl3S5DX0Ouut+EP YhBo9YcN9H4jvLUIjWCYpDAVBgYrgQQBCwEwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYjI3A 1ntItCnh+iM/f7sBdkjkcsZSUG0FMIAGCSqGSIb3DQEHATAfBgsqgwiMmks9AQEB AgQQxE+F/5gZnVd42/D7Aedt/qCABBBkwbOOfBBol40r2KyPQjNYAAAAAAAAAAAA AA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE sjMsUNnWUgIDCJrffiDuZwu9fpq7A6X5qUIJojvFQ4352D3aCXEenPRQA4g1lueU clTZ4AEEHsBFK9Kf9OOuFjAVBgYrgQQBCwIwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYCd15 aJPiSbeZi0tpLI4bQcQLO1YnO2ihMIAGCSqGSIb3DQEHATAfBgsqgwiMmks9AQEB AgQQ3T5S3rr68icu+5ADc9ybuKCABBALA6cpuh3nLIQ4Vk1VD7JdAAAAAAAAAAAA AA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE ng41pqn3itTDqqaQ/6J/owpC8pEUG46nDlZuRe1Kf4dehXB4KXxYilDPx/30iJCr wwzOMEqRtCSY3I9nTWYt6TAVBgYrgQQBCwMwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQY6qCH eLq93ENMbdTZ6MnFf+6BZSEDyF0CMIAGCSqGSIb3DQEHATAfBgsqgwiMmks9AQEB AgQQmG/EqB4VbniISb63N/G5U6CABBBab0am0A2aCM7JL8XHHg2tAAAAAAAAAAAA AA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcGhgb4CAQOgUaFPMAkGByqGSM49AgEDQgAE OdnaWWIsuEaRaXJQPvhGSbUuQqJjFcEFusalzcbMIidDhpeqQg4mWv72SjzG58vU 8iH0V8Kjson8PJUNsRRfTDAYBgkrgQUQhkg/AAIwCwYJYIZIAWUDBAEFMEwwSjAu MCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQY LH4G/It9nl67Zl+enoPNBPZJerfVCMogMIAGCSqGSIb3DQEHATAZBggqhkiG9w0D AjANAgE6BAgh8q9PcJRPNKCABAi3G7yWwrgscwQIY7upGF32NTUAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE e1+bTztfsOpSYLn+adO9a1Ooem6HFGvV8bBppQwi9F+kGu1rTVCQx9qUzgmHETDK 54R1V1V5a2TOUR8xdu1g9TAVBgYrgQQBCwAwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYovcD YG2K0JYETFJorRoHtgYjKkSi7egYMIAGCSqGSIb3DQEHATAZBggqhkiG9w0DAjAN AgE6BAjUb4iafUjk8aCABAhRNyVhrpHzmwQI8XDonroDuXYAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE FoMnzbf1oXZjFOTtqUDsSWymBrNmHzO3gL+m01VIGnkiFj8EejvCxrPNjabce6TC chKlhlDLxdhmb8Mtt52DIjAVBgYrgQQBCwEwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYkDI+ rlPoNxu7WoPB9Sgsejhw94pY7oapMIAGCSqGSIb3DQEHATAZBggqhkiG9w0DAjAN AgE6BAiwmRI7w+U7w6CABAhqrIOiZHWGUAQIzOlO4nvZn5gAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE +R9I7CJUNznNxDGiC8cR9qIXZyVK/0clHFtZctKwMQeJ8BEzsFtmAiA97sf9H6E3 4A8YwgrzeQod4TVDJ0yw3jAVBgYrgQQBCwIwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQY8/8O JKxrUwuqe0mvpJewQk5BCmd/TTsnMIAGCSqGSIb3DQEHATAZBggqhkiG9w0DAjAN AgE6BAiHKjbBK3DWiaCABAhCm9TeCCBdowQIbAtKUdN4fn4AAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE Mhh6OfMp/kG2xWP4P5p443DBYkcgodaH5+P7eaUuKzb+BCfrXuHhVapcWSEWBpYf IXUYk6NO8atarZ2ruCaznjAVBgYrgQQBCwMwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYIQek muKfqohyH3VwQgfnQWBDEgHt8VKnMIAGCSqGSIb3DQEHATAZBggqhkiG9w0DAjAN AgE6BAhBAkTfDryDRKCABAicY2DaqZeobAQIpdbjoyUY04cAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcGhgb4CAQOgUaFPMAkGByqGSM49AgEDQgAE FKrA/1HA1yvJiDynCweQ1qr8BohYtxNa3KjCGZ+fwbzEMB+FP4aqVB9WbRIaE6MO cAPnbew9gsoj4aZyJ7Ik5zAYBgkrgQUQhkg/AAIwCwYJYIZIAWUDBAEFMEwwSjAu MCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQY xEEeQbm5Q2NfSU21+fPj8vsSEG/vq3EAMIAGCSqGSIb3DQEHATANBglghkgBZQME AQEEAKCABBDUnRs2t79NIjljXEwG/sAMAAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE 1EMpS8ICvJ7JKEnf5i9vTmMfK5yA2urR2+Ta3x6rG/flWRU4p8taH7niLkbMkITK ADwwoYTidQpBGuozWCayrDAVBgYrgQQBCwAwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYM21g lr4ePPZtMp5Zy3NtbA73j+idtew6MIAGCSqGSIb3DQEHATANBglghkgBZQMEAQEE AKCABBCfRV7RN4fpIH3Yg+NgyCTzAAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE 98WX7RssBk6i+iQ2TFGU7bf5JzCOrs413QXgWn8ehHpyPYbqECR8sO3yb/ThrpHO ypQcFTyAJSha2BHbmXGnCjAVBgYrgQQBCwEwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYpeNN d4eEr09mBNEFQsBwXPlDV52OW5ybMIAGCSqGSIb3DQEHATANBglghkgBZQMEAQEE AKCABBDEYG1WVg9zU+GtID6Z62MVAAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE SdXuTrXQjAV8G+iLGPSGUc7J7/aCLT/w+ySjN3c+ps1bTgU9nDnrvZ0GyaJpMNGl gqmkDg2Ju4BD6+qoLX4LZzAVBgYrgQQBCwIwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYyew3 isNLa6VVuOLExAbh6/fneOj2HCamMIAGCSqGSIb3DQEHATANBglghkgBZQMEAQEE AKCABBDSe/7UBhgGj8KRH39gK5xWAAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE RLdf7BdnFnkVG+Q7V9kfmR/FlJTDBd9equqyvQIPeY4/+d6KIkwrjZ1uGRGnOsH+ L5+uawKIXwqzCDzIF8Nj8jAVBgYrgQQBCwMwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYaWsb /pW8CgyafVs7KfkXryp33BN7XRmaMIAGCSqGSIb3DQEHATANBglghkgBZQMEAQEE AKCABBAncG9TyQN/m4tJYLSBo3qAAAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcmhgcYCAQOgUaFPMAkGByqGSM49AgEDQgAE Zw0Y6ktKR60a3WTOG72NTQc1IKKaMQTK71GYgOjOq5uVW1lZHglu4GPBrIM9hGt2 SsFIP5KvoD9ts7Btyt5wEDAYBgkrgQUQhkg/AAIwCwYJYIZIAWUDBAEZMFQwUjAu MCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQg 31p1xsISU0KVexH6MSvU4u+MDhtuYz6ooa/Cky8crDgwgAYJKoZIhvcNAQcBMA0G CWCGSAFlAwQBFQQAoIAEEMan0t82ejdJdRnOLHPvi44AAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcahgcMCAQOgUaFPMAkGByqGSM49AgEDQgAE IVubQBzSV1SSvJk2ab3mxJ7AkxR2UgilIvujEWK4iGBE2iODGULyg5VKRZArZbyK OEXOZEBr29QIHjffEuAHLTAVBgYrgQQBCwAwCwYJYIZIAWUDBAEZMFQwUjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQgxJ7R HSSWI3wgOljuIywmFA4SSxOrqa7URLF8az6cvmwwgAYJKoZIhvcNAQcBMA0GCWCG SAFlAwQBFQQAoIAEEDjiS0Z7OhplQiXkzZD4DGAAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcahgcMCAQOgUaFPMAkGByqGSM49AgEDQgAE 6FLvzaA0WyjIgi7epe2VkiCoTVb4ky2E23AG6u4NkDjbvlG/B+MF0TEmtW5SxAJD qUI4EghJcGX2BQ4+UgBi3jAVBgYrgQQBCwEwCwYJYIZIAWUDBAEZMFQwUjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQgfLT2 rgPa4JlW8TL8YW30M8m+wxACPAMeAT8TDDYO0WAwgAYJKoZIhvcNAQcBMA0GCWCG SAFlAwQBFQQAoIAEEG/qcW4KawEUK0HeOpq4ZdEAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcahgcMCAQOgUaFPMAkGByqGSM49AgEDQgAE DVwSKP2BsrinZaF4tlt7ZjRq59l05bF6PqY+9Z0fYJ03dXAM8VsSyEAVqTxbHNTj nFWE2C8miuA7r7c8M5JuhjAVBgYrgQQBCwIwCwYJYIZIAWUDBAEZMFQwUjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQgQ134 rLBOz3ljqJYBuKTzB2BHi2WdJgR3viPkooC/998wgAYJKoZIhvcNAQcBMA0GCWCG SAFlAwQBFQQAoIAEEOMBdbXo7mwTCJLyOU6MvtwAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcahgcMCAQOgUaFPMAkGByqGSM49AgEDQgAE xGLdCxmNHwUvIU7BICPdFvIo0+owMOU05HygkoMMIQZxvOVTpzS/2GY1wc7SRyeN 5+fOiZCN7v8E9CSCKsTJDzAVBgYrgQQBCwMwCwYJYIZIAWUDBAEZMFQwUjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQgRoQC VMoHH5IbQzg3vS9Aw3mCGQ36uKpWrs6EjSryfxkwgAYJKoZIhvcNAQcBMA0GCWCG SAFlAwQBFQQAoIAEEB6FNYftgZazlVG+9VmWGlgAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgdGhgc4CAQOgUaFPMAkGByqGSM49AgEDQgAE Mf4KLGdDuedxTSZmmF4J9+2pQh8AOrQJnR4TVmiXLCddrlj2fJPwB4n74fHNmXYe T1A35DVGtXUWYZaFbHfh0TAYBgkrgQUQhkg/AAIwCwYJYIZIAWUDBAEtMFwwWjAu MCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQo aJolf029cD3lfGip8jgUWQoK+FbU1Wh7Ir6Vn6+PDLZVFHch+RsgIjCABgkqhkiG 9w0BBwEwDQYJYIZIAWUDBAEpBACggAQQZB1VdS5wydzSW/Oow/7MvwAAAAAAAAAA AAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgc6hgcsCAQOgUaFPMAkGByqGSM49AgEDQgAE zLajMBAMGJiYDQIoeCr+5Pf1m4rVvZPStzJteLEolwrapZXPes5IlBZQ03k/9fab vAmcnWjP6murHML2UjKsLTAVBgYrgQQBCwAwCwYJYIZIAWUDBAEtMFwwWjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQoLxA2 jh7WPxVl57x8E/k0DgyWzErCeCuQgNIwS48DtIBoYos5A98KITCABgkqhkiG9w0B BwEwDQYJYIZIAWUDBAEpBACggAQQ6a85Gcfmaz8GUP3Vs15n3AAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgc6hgcsCAQOgUaFPMAkGByqGSM49AgEDQgAE MfV71Ca9sLSoOaL/UGNPH8+4r8AG2tGkOtQ0S7g09BCAuhqoztWPThZkcPoFJTkD DEojhHUvlRorZFvjFw7NVTAVBgYrgQQBCwEwCwYJYIZIAWUDBAEtMFwwWjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQopfRd PBICOge2lZsJZPJsxoldBjUCsBOHuEBEPERic0NmCbWWRO8YOjCABgkqhkiG9w0B BwEwDQYJYIZIAWUDBAEpBACggAQQkAAwrvxK9Mb9R/MuXaJkYQAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgc6hgcsCAQOgUaFPMAkGByqGSM49AgEDQgAE 63G8cn63oUtF1QgvckQ7DdPtD8oRPAYcymF7avKPqzpKbIHm6mFNOparhbNNhaLn zJB+w0oQVJe85AL09eEOYzAVBgYrgQQBCwIwCwYJYIZIAWUDBAEtMFwwWjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQox/vj Z7M5hgXcSmGsqoW8aOCUX8GdPZRFpUhitVnjZ1Q1GDoLZwwM0zCABgkqhkiG9w0B BwEwDQYJYIZIAWUDBAEpBACggAQQcX4IWuRvjN7CpVcGkj3izgAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgc6hgcsCAQOgUaFPMAkGByqGSM49AgEDQgAE efrLjBFWs/12kCjSqL03WEaPlRtpgTyLpCbPDc29nFBFcIiIR62cRUpZGuo64rAE n69T0nmkW1f0gPVeKvbMNTAVBgYrgQQBCwMwCwYJYIZIAWUDBAEtMFwwWjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQo3qaN UAxakRXZmNQR0PIxxQg56V5MrhxKtMAVIyQccYPNhsM/Lap74jCABgkqhkiG9w0B BwEwDQYJYIZIAWUDBAEpBACggAQQK8er40y4+VxfVyAFHD+eqAAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgcGhgb4CAQOgUaFPMAkGByqGSM49AgEDQgAE X1veoS45kW4a0IppN/WS/hnK5xPY91Vy2jIw+edev/HiAVaebyN9BapW4YeELHxt VYcIXZZ/o4rW/jDcAXUFSzAYBgkrgQUQhkg/AAIwCwYJYIZIAWUDBAEFMEwwSjAu MCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQY hyqSIsSGvtV3T0H9AXWRdlhJI6Ri5eZFMIAGCSqGSIb3DQEHATAMBggDojEFAwEJ AQQAoIAEECAF2uY94Anbr0lhM4tYzdoAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE 8zN8f1hdBCp7Tk1xVJWEw5WmsdQ+AY0hpnQL9FMvu3/BUKTx59SfTyi+VI8q7wtK W+OqqFhY4qb7mSY0qFdttTAVBgYrgQQBCwAwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYSWYc zbbIQhLX251LeuCLfHPa9/r+pobmMIAGCSqGSIb3DQEHATAMBggDojEFAwEJAQQA oIAEEGMid1kywhmcLeRfdeSIXIMAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE 47qJqR+LpLp69XPlUC//5b/pQOrMadqMPJvd7siWpZvRukn5BuC103f2g9BKGt1z o/WlNfQkDC/XuyuUYEFlMTAVBgYrgQQBCwEwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYcCIH Mrt5GhLAOqbBiLh0LzSBn1okQT72MIAGCSqGSIb3DQEHATAMBggDojEFAwEJAQQA oIAEEDyfyYVCDlUQLaWR5WdNwt0AAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE G2RJOMvnDAjbk1QvmNXcXDWus++MXwfu7Rsvp4YaFzLh9Z4gVpqrJjp114VYKfou G+AnSSu7vkPyU7Q2uo/LnjAVBgYrgQQBCwIwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQYbPxf nTi9+GDRoFAoBnUugDcyzzRW8riXMIAGCSqGSIb3DQEHATAMBggDojEFAwEJAQQA oIAEEIJKU14QW/1QFQVqqOL/DroAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxgb6hgbsCAQOgUaFPMAkGByqGSM49AgEDQgAE 8dNbdrNgOMn0mfcRBiCu4CSN71lr69qTZtLTIK4wyM/8w9FbLG7dT3ohPVBcyvA3 krJx+nWZ0KGEx/UbgvlYeTAVBgYrgQQBCwMwCwYJYIZIAWUDBAEFMEwwSjAuMCEx HzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+AAQY6mbx Dm6+bvjDHV9Nt64Z7iu99EGIKmdZMIAGCSqGSIb3DQEHATAMBggDojEFAwEJAQQA oIAEEL2k2+wh+Y/7eEwILV26SN0AAAAAAAAAAAAA -----END CMS----- cryptostore-0.3.1.0/tests/files/cms-enveloped-kekri-data.pem0000644000000000000000000000501107346545000022156 0ustar0000000000000000-----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxOaI3AgEEMAMEATAwCwYJYIZIAWUDBAEZBCDo yhBOcZqwXnAfeiaK52eDsGrKOL85GeJrvvcY9FRBmjCABgkqhkiG9w0BBwEwFAYI KoZIhvcNAwcECLWFN6cve5wEoIAECM40Ls/E6HzYBAhHv8Jip9pQvAAAAAAAAAAA AAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxMaIvAgEEMAMEATAwCwYJYIZIAWUDBAEFBBgQ 8hblrCFtOKfFY9dCk8aI6gPI38gNxb4wgAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQB AgQQgKp1jEsgtoJBBCTFFr7ZW6CABBAAueS9/IDW7qkoAAnwJa6sAAAAAAAAAAAA AA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxOaI3AgEEMAMEATAwCwYJYIZIAWUDBAEZBCCJ KIFyLbTVDm9cRYy8OhTixgVwfO872a/hEec+o1e1cjCABgkqhkiG9w0BBwEwHQYJ YIZIAWUDBAEWBBAITkDG0u/WajB6DDvRausgoIAEEJdaa0ftXKLB3M5rjxbGEU8A AAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxQaI/AgEEMAMEATAwCwYJYIZIAWUDBAEtBCha 4D9Jno+cmNYSVvWeOM6m2NgfmddUwIgyoWpbOgd727KQWIBV1AudMIAGCSqGSIb3 DQEHATAdBglghkgBZQMEASoEEMe06a1kNuV6tFSHGF2wefGggAQQPMxzB77x7i8v S1HjzJQPwQAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxMaIvAgEEMAMEATAwCwYJYIZIAWUDBAEFBBiA +8fCiPHEAnws9D7EEaXyprJ5ISGc5WwwgAYJKoZIhvcNAQcBMBUGCSqGSIb2fQdC CgQI9WVhp5WQBPaggAQIxOvRdqE49+MECORNVFB5xgh/AAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxMaIvAgEEMAMEATAwCwYJYIZIAWUDBAEFBBhA 1PEjPE41AFYjPsRETxh1qYmsD81bJoIwgAYJKoZIhvcNAQcBMB8GCyqDCIyaSz0B AQECBBB9knlsBp0PF8VO/Vq6I3dMoIAEEC8p1Q7tahAgvESPigwUWUQAAAAAAAAA AAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxMaIvAgEEMAMEATAwCwYJYIZIAWUDBAEFBBgc 46l8i23oY5lls3xc/VZMqO/K/8XUMhkwgAYJKoZIhvcNAQcBMBkGCCqGSIb3DQMC MA0CAToECJw92yJUyRuboIAECHT/xgVF+GKdBAhwAQsKUzbU+AAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxMaIvAgEEMAMEATAwCwYJYIZIAWUDBAEFBBhy j3gZd5BrG1Uiyck1oCi/lbnFbm5ozFEwgAYJKoZIhvcNAQcBMA0GCWCGSAFlAwQB AQQAoIAEELsU0eo7AL8kWQrzaV03dWkAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxOaI3AgEEMAMEATAwCwYJYIZIAWUDBAEZBCAq fkHN7tQE8sIHZBwnAlhauh6soXEJ1rHgYZvK4ZZnxjCABgkqhkiG9w0BBwEwDQYJ YIZIAWUDBAEVBACggAQQYJueGyUSbvpvVwZPwuUDSAAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxQaI/AgEEMAMEATAwCwYJYIZIAWUDBAEtBCgA KHatZAiCdMZkRJ5wqivOUiTtKGmiQtXN3QqJJJ5aLRoqEJkjz3qWMIAGCSqGSIb3 DQEHATANBglghkgBZQMEASkEAKCABBComLWQrUf7us505ifmrkIvAAAAAAAAAAAA AA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQIxMaIvAgEEMAMEATAwCwYJYIZIAWUDBAEFBBg1 ZjFOAC8jaQGoniHQjMwwg8JAzXZ5uhkwgAYJKoZIhvcNAQcBMAwGCAOiMQUDAQkB BACggAQQvuQ6f0WV5jQiaoQDFib11QAAAAAAAAAAAAA= -----END CMS----- cryptostore-0.3.1.0/tests/files/cms-enveloped-ktri-data.pem0000644000000000000000000002244607346545000022035 0ustar0000000000000000-----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEBBQAEgYAS MzqnxC+lVY9dcFRygAur41ttkbkparQlMeSq9yXnFA/vs+9wJFFYjl/RKfv76Mp+ YM90kPizFeXfMIpCZ+r3+xcE0JQPdRiMICtQXugEJcwRH/YOGM37EFG6sJlNaC8i VCfO5Uf7zx51064dPkj2aNvgQhX27ZT7dmGWprVbozCABgkqhkiG9w0BBwEwFAYI KoZIhvcNAwcECMLnvaBuUHSpoIAECG+eWrhA2KNoBAg3CK4ewLznOQAAAAAAAAAA AAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEHMAAEgYA2 f8wQrnm1bik0Ayomu5qJmjDaK/dyLLWXROHH31QoF/2dOiuPYWlFgYdY0sRPDHBJ lVDtpq0BLBkK8VG4XQ/YhzhGkFNzlTgsrxdMjrd7aBmbQWm5sxsmFrirw2BtVF2I tQhFoCAfhBt+b/PitKQBfFW7Ky2MklqGCdqYzJqO8zCABgkqhkiG9w0BBwEwFAYI KoZIhvcNAwcECMLV/HRrNrefoIAECDVAEsd2agZbBAg+Ifn0uwVIsgAAAAAAAAAA AAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEBBQAEgYBU MLcA5XvSs4vKd7mP1C2b6eauX9EJvhqC33rQreL499JKamowq4DiwfHTuSKOpriV +2IGVC7waWS2NTItCwbaKzp/vD2GZp/QJM1W3CsYyoL+3NrTHQNrsi1lwIdhhuUX SpJA4Ep5Z3cFSf6PzfJJ/O+1lZYvw9EX52LB020wGjCABgkqhkiG9w0BBwEwHQYJ YIZIAWUDBAECBBArtuzIoHJMe5PxCGdiU4oQoIAEEOWPlgTT81fpjrOFvFMQDtcA AAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEHMAAEgYB3 cVqZNKioiVkMnWltmseu68l9iewiVjOWBmN1KMFVniFKWs9yAytReEQn+9UxC2co TBtnDEf3F5b49/TGE5r0f35NNPjq5fUEasyHSxEdyQtXoTWSB3dVACHajD04jHCX +cRcGGdZHvC3tsk4701FBHj9p3wwZAdbL5XzvvYPvDCABgkqhkiG9w0BBwEwHQYJ YIZIAWUDBAECBBAC2LihEql1ziAXXDoufcIcoIAEEHoRrnR1WOV+rdwzSi3pVbYA AAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEBBQAEgYAA /9BE5hsBwMbQKNE4y5VqvoalUMA9KLmBWGkNkTC9u6gLYbUAIiGM6lPl4tMkQI1Z kQI6Mhce9qlcScfvs4+F5S/TdHroojb+63UQegUN5VQP3rO42JVJ9zTA/ai1Qtib f4MKtrpwLcNZf3t2VC92pUpijNT3u10MUGCoSOegqzCABgkqhkiG9w0BBwEwHQYJ YIZIAWUDBAEWBBDESQ54qb/ShKAkOsNIumAcoIAEEHo2fCHz6SHY/Sv8hypILG4A AAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEHMAAEgYCb /ANiTPLkI+P9HKKjyt9JeT5ekyYp5RMREW4OJncVvDtcol4SjAFtcFW2bud+WRvA qH80qw7Z0HCwUNcGJVKDCBXEhbLv7ft3Y8ii/i+CrtN07KnK4hnl304U4/B6LbaM gwhx3zJU3eA+Qu7Aih9mDS/ZrzFpxmP5cFkdidsiKTCABgkqhkiG9w0BBwEwHQYJ YIZIAWUDBAEWBBDXgCwZw8Slrzewlyr9pavGoIAEEH4z5teHfvFrCfJ30jzFjC0A AAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEBBQAEgYBz 5yZVvclHOaLiwiKD5CLmQA2xpCcGPr5yh/ToKjjgufVuKurl6iNkAYfKbmHDzOyK MbbpYtpiK6+AWcO+JtHJZJ2/4P1JYBJ67amdR20BvKm5X15q8Z1K015U2g1iIlUe 8Jzg2EwalofNGnR8vcBrhnXdaOi1lnhl79QBAbvg5zCABgkqhkiG9w0BBwEwHQYJ YIZIAWUDBAEqBBDSlU6mD+hEt2wJ77zZ+Mw9oIAEEMCfkTPDAb48ChJkr4pyIIEA AAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEHMAAEgYCZ QhZLfWRQohqi11gGijjooRnoAl1r1Q+qnXUTEy39Z0riCBmMPSyfrxtnKbQq4Ytp zUKBxksMsSEJdO0Itn9cfgYoSAaz2j+wLgMMRQhAskNdUCRNY5wj0rQDrJEp4Xr0 hTovfkk9JjITxQ/rcjcyKPCjMYhaAe96boq0gf5VezCABgkqhkiG9w0BBwEwHQYJ YIZIAWUDBAEqBBAMMb42cklST7NGdvqEKnxMoIAEEEHy3lZS0S0aRn7s9ZBZDwUA AAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEBBQAEgYAK FaLR4MUy6vjIf1GMZ/ljgEjijfF0eV8m5sML+1SJY09/WZ02g4DDZ56eEVlHV8SP GnkxU98apWm7LBj0acNsQtuTGgNRCxsiuxVtqmFx/6wcW26T5Hnz3qgFFGuXQz3G 6DamGqw5DcZhcKsa5rKcGE9LV84ih7U8648TbjTO3jCABgkqhkiG9w0BBwEwFQYJ KoZIhvZ9B0IKBAgBIxu0kwTj/aCABAgesQ0q46GB7wQIKigIcZYvAwEAAAAAAAAA AAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEHMAAEgYAu zqzksttaYanHXGNdA1lbrdJMDO19mqIIq0bNuNnNRhi8gkVqiaYSx4jWWihynxvp EYj2+VQ9DSYWAN6A5A4RoA5xm7pitXl/lhBdgpe6fCLFwXs5HY8LKkqzIn3MMWOf j1vCuZjuUZT1yvZuhnGOk5cua468OHZjF3SCjdCxAjCABgkqhkiG9w0BBwEwFQYJ KoZIhvZ9B0IKBAh4qFkOcAm0eaCABAhUZQxFQ+ja7wQIhxDypyzXMeYAAAAAAAAA AAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEBBQAEgYAp 7601Ats7XLYQopjKo4X92vK1vpqiV9fo8qcAd6Fo61SEgAPTV4ynHOYzUjDHCTbv zFQ6M80t5igMpppmcMc6Rs1y/atpMIWYMTDvCFxLN9iYvwbwq5xuTgsKpBs2s/OJ FRDkSOEsBWGHhlaa0JDzfSqPFxO0UnlpkaWxhm56yzCABgkqhkiG9w0BBwEwHwYL KoMIjJpLPQEBAQIEELe9YYPj5Ndvaj2thJc4oZaggAQQySVpbfUQPXsnKZ2j3Clj DwAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEHMAAEgYCf M58lS+xD60ThkV/KlhskCQbzYa5tgoMbQaRF1Z5PQoCWH+iueOH83DkwOiatBcX4 4gb46G6aItDCMyG18v3t0x/DnE+FAEsxucG5iQYBjW+AhaK0O6H1/q7i6j9je46A L2YPjK638yb5y34IRcJJWSFqe31SLQdVAIP/fIFGizCABgkqhkiG9w0BBwEwHwYL KoMIjJpLPQEBAQIEEOQN2AAuDs3ZKl2RLJb9F0aggAQQFQ2VgsBc8tufBxFTJPlw RAAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEBBQAEgYBY EtN5fKcxlW4w+XFlXXCuU+MKgxn6hgDXyfOSNaInIvlTvJ+H1RZfykFo7FdzPvNn VLVoegnJSEwdxe/zdl3sxN/V8LIS3fs4mCXQIyA5tsrYHjTHMYojCTmzpWvy2/JF L2auV3+kjaIve1uEeIxk0oHmPmIPiMDb13eoLvdJ/DCABgkqhkiG9w0BBwEwGQYI KoZIhvcNAwIwDQIBOgQIQ0hQOhF2kRyggAQIJPO3RK4NI88ECE1+ZS8fRrBhAAAA AAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEHMAAEgYBi KZHomluvWpI3YchpacGbj7OFsB6Q5sETL8WzJAiLAgoYOwvWpVYb2PbgVkEpGgs1 a6xEyz2afKXKdPEc4DK3sGfnM3Lz9Txz8In3d1jAQBXLZl8EoaZQUO5VeD6IvYil GU8aPgr+Snu09kKqYdkyNDlCUvqP1ncYNqmFLYNAkjCABgkqhkiG9w0BBwEwGQYI KoZIhvcNAwIwDQIBOgQIlrnglIwapsuggAQI3kKGphwDsXEECC1RfvxIP2+aAAAA AAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEBBQAEgYBq P+U1MaRiR82vFKuH6y/apL26VHmkoxNlsODr1UxSdqpLLnk2NHUcef2J6ZL/NsCQ J84yKvcWzw6hqS9II9e4KK51MNWjf40T/fWOfDHiVZ0/xc+7AEhiA7jdow2Oiw8F FQBZmob310njFzCWpyoJv06I6WhI/2qEuzkBZpjlbzCABgkqhkiG9w0BBwEwDQYJ YIZIAWUDBAEBBACggAQQdRO+ksa4ijjcxJCg53aCdQAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEHMAAEgYAg vYGS4TlPOZ9ttdCX6p8D/JMEoajtCe0HeTLsax2Skdz9VnEyhrGUhqfy43qrraO2 N7+o/tHCGa7BpFvM2UfzsF/0KJZsyv9G7txUBEEhYmjMVsZ2QYwAnIgTH95ucWnY We04KNRqbxV52EUs1LgOZSLTzbLrvGXPvtsSBKVzzDCABgkqhkiG9w0BBwEwDQYJ YIZIAWUDBAEBBACggAQQyePr0+JPuJ2d0zaw1HqCeAAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEBBQAEgYAE RECUSsy4tlI9UsIPxUEx6GRBeb0YhlZP6HqUwU2zx76/cm5M3aD6n8XTcNkl8mxG 7OhGi0884x3uDjihq3YzLgLKTgQ5htnu8frGtAMe4s8MkZ7i3ECBM4HdSLNesvwY hyJ2fYatRRaTCvYVGTcQ+mrIvRRSYVokLRZzwFqpGjCABgkqhkiG9w0BBwEwDQYJ YIZIAWUDBAEVBACggAQQnWARpt02jOj8d2M70gXM4QAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEHMAAEgYBv 7rTFST/R7PDsDVm17MQArHteoRUewIAVkbWkd8iB5FFJXSXGxtIs+DtpUqq91z0k O5hL4wIzRYUebVvE9XMot2kZQ2PAymX5B1EM0MRc2XFrBOi1Vkq6jCEdow4yedNF UL3IhtT9YTErSvK+2c2r/GeBy5oAM+qosCZpk9c2kDCABgkqhkiG9w0BBwEwDQYJ YIZIAWUDBAEVBACggAQQ2QnNQVPLo9Um6plRZP9kogAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEBBQAEgYB7 eybuQWl10p2u2XcrGTHeMYFCvcYNO4NLxFogIRppPRehQhtXGtO38FhjYuj0eNZO XP7oaJJFuVTir+YDZdhmUuuDgYKAWmpVEiAhqQBh5ZX6k8HY+h1vdCxs6M27ZXyG zsihIjxXoJLZh7yXcZMHJOrl2Oi7bDXRSQ/70JPktDCABgkqhkiG9w0BBwEwDQYJ YIZIAWUDBAEpBACggAQQ5dd51/ShE4xyqxr2v/QcPgAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEHMAAEgYBq ZKmAhfw2n/2PlcbL6jbMB2PNmX0mu/DTqOssmBExIUqq1R31RlOZ5X799R9XUGMk 0CzsolL06nhNFSeFK9wqkbljpA6X2UoVKhMe+xc6YNuDa4EGLNfE+hvmiJtVuTir HHB6Ke/xRXrPTH713yYQFnJUq7JV3YK0r/yCqO23+jCABgkqhkiG9w0BBwEwDQYJ YIZIAWUDBAEpBACggAQQ76KVR7qeUnzHe+A0Q0zyWgAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEBBQAEgYBZ OPbl/h6GxeJE5K+5T4cKBaBd9gDOhkXssk8ahr0ykZkJj6XXEUaae9qFO1wmljDe bcrMkFtiIwcT74A/qO3sStqEzFtb2qKxqNQg3doFRGQe5H85B7yQI1sPoVUVrvy+ 4YPj2pUNdUXMvCWB/rQTyu6ZN4rnVzuC4GnuXIwoPjCABgkqhkiG9w0BBwEwDAYI A6IxBQMBCQEEAKCABBD5WfiWV6XIOjnWwW5F+H91AAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQAxgcgwgcUCAQAwLjAhMR8wHQYJKoZIhvcNAQkB FhB0ZXN0QGV4YW1wbGUuY29tAgkA9w3rWSwpN5swDQYJKoZIhvcNAQEHMAAEgYAY fXUCemSM4z3r4HVcPtqtgHf61MXgH9yoMT2N9MFyolYSvPjUMhrzKHgcmbWmXWG4 Msj3Kp3HknvlT680Sf2PCLSuemJ55OAc4b20Y+E0kawK/Y7Kk6662Ic/4nAANYCT OPMPuM+qHtRFiCyS7ley4SdvtfkUqa2ylpWjLudiATCABgkqhkiG9w0BBwEwDAYI A6IxBQMBCQEEAKCABBAnhuYJW+U0RMPg47sdKrbyAAAAAAAAAAAAAA== -----END CMS----- cryptostore-0.3.1.0/tests/files/cms-enveloped-pwri-data.pem0000644000000000000000000000426407346545000022043 0ustar0000000000000000-----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQMxaaNnAgEAoBsGCSqGSIb3DQEFDDAOBAjGmdvq OEXsfgICCAAwIwYLKoZIhvcNAQkQAwkwFAYIKoZIhvcNAwcECBqgquyBZfiyBCCB e8Znem9EJyy35ISVMOTFu1zPV6F2Ct+GzQWZLtVl3TCABgkqhkiG9w0BBwEwFAYI KoZIhvcNAwcECJpn34+AbNP3oIAECOTmA1ktv97ZBAjeeFTRB8REdgAAAAAAAAAA AAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQMxcqNwAgEAoBsGCSqGSIb3DQEFDDAOBAg459s2 DKHMTwICCAAwLAYLKoZIhvcNAQkQAwkwHQYJYIZIAWUDBAECBBB5IgIXJlXboBd5 0Ul1hadfBCBmiHy9CnC6/EfTVW8P6WuY7HxO5M9uFpSV7DwNqqra0jCABgkqhkiG 9w0BBwEwHQYJYIZIAWUDBAECBBC9IWSavohVALU9BchvHMY/oIAEEE+4aWPxtady Yv+HK8CNj+AAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQMxcqNwAgEAoBsGCSqGSIb3DQEFDDAOBAhMLyN3 9SEyeQICCAAwLAYLKoZIhvcNAQkQAwkwHQYJYIZIAWUDBAEWBBDGLmHK9CHO4OVf MSaHJ+FaBCACC4FO2u1LYSpaFmGUMRvL3muwJrm4ZTtx/o0/siV7XTCABgkqhkiG 9w0BBwEwHQYJYIZIAWUDBAEWBBC/6PTDboiGM4pcWVHGMtzYoIAEEE6ZQvaKhESN cVjWjOW3m5AAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQMxgYOjgYACAQCgGwYJKoZIhvcNAQUMMA4ECJEM 2A6yA3hOAgIIADAsBgsqhkiG9w0BCRADCTAdBglghkgBZQMEASoEECfPlNUFouJ0 0Udxr18xzuAEMAEaXXJinmZg6eAMWQbgmRavVidgxq1M0hm1YSnDSsl+onNA1okI FC3updaHmEPpJTCABgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCbfmx6jQ7nNTqb t98Phnm+oIAEEC50vNvKr11yid3OHO/N68wAAAAAAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQMxYqNgAgEAoBsGCSqGSIb3DQEFDDAOBAhgcukM kY+kAAICCAAwJAYLKoZIhvcNAQkQAwkwFQYJKoZIhvZ9B0IKBAgx5KKRkXFNHQQY mfBZc9TEe7xuV3NUmt1SCpndkttyibGlMIAGCSqGSIb3DQEHATAVBgkqhkiG9n0H QgoECAweaGrM2MHCoIAECC8nHwrprn5KBAiAVC6ryHwFrwAAAAAAAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQMxdKNyAgEAoBsGCSqGSIb3DQEFDDAOBAjE4jm+ WpxP1AICCAAwLgYLKoZIhvcNAQkQAwkwHwYLKoMIjJpLPQEBAQIEEHxIjOP4CIXt mT9aFIQEK4sEINlZLo9mVM/SoJ8f+HbGolEzKiof+yb6tDZVb3Qz2Mx+MIAGCSqG SIb3DQEHATAfBgsqgwiMmks9AQEBAgQQYuHF+dgR4zM+zPT6Oa0yPqCABBDDyZL/ 47IMaP6UDK1SNJKkAAAAAAAAAAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHA6CAMIACAQMxZqNkAgEAoBsGCSqGSIb3DQEFDDAOBAjKpTDQ /9Z3LgICCAAwKAYLKoZIhvcNAQkQAwkwGQYIKoZIhvcNAwIwDQIBOgQIxvVzbjAh 9lkEGKYC5xLJK6gZ0xCt/8V2+pi5bubgOAzryDCABgkqhkiG9w0BBwEwGQYIKoZI hvcNAwIwDQIBOgQI66/5xUVNrc6ggAQIRVTFbqLaTjsECH6CEr5uv0DJAAAAAAAA AAAAAA== -----END CMS----- cryptostore-0.3.1.0/tests/files/cms-signed-data-detached.pem0000644000000000000000000001612407346545000022111 0ustar0000000000000000-----BEGIN CMS----- MIIECwYJKoZIhvcNAQcCoIID/DCCA/gCAQExDTALBglghkgBZQMEAgEwCwYJKoZI hvcNAQcBoIICFDCCAhAwggF5oAMCAQICCQD3DetZLCk3mzANBgkqhkiG9w0BAQsF ADAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMB4XDTE4MDcwMTA5 MzUxNFoXDTE4MDczMTA5MzUxNFowITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFt cGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtBG2kKWfYT1jUXmb DlrkD3Wfw0rKDjTdjjSswM2HggMtEbiutc+cxnoW+DaeP1SzSdY7NXlaqvzftCPL vzJNaRM4HpG/XLqIdub5hzisbrwN1/Q77zmUvr1ka7NaXKZDuuepORJsNh5lHkp2 2VR0O0pQ3zLNjX8IVAGkdpoE5iMCAwEAAaNQME4wHQYDVR0OBBYEFPyU0yv/vEPO p1kMDzLvtT6U+gYOMB8GA1UdIwQYMBaAFPyU0yv/vEPOp1kMDzLvtT6U+gYOMAwG A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEAn2yZT/WNupO34PxVdWU65X9q mCE4AtZKLbRa0iSkkEY961oqDiMVWiaN0sPVeV1GoNCz9J8lLKaEkR8b0F4KlJ0K 44V+5P0Hvb1UnKV2SsNxkmNbxwjO8Q+9aNjd4IqxAnSyQ45yMN4K5x1COJFXQETJ ApFWhLZxgA0hqnotQGcxggG9MIIBuQIBATAuMCExHzAdBgkqhkiG9w0BCQEWEHRl c3RAZXhhbXBsZS5jb20CCQD3DetZLCk3mzALBglghkgBZQMEAgGggeQwGAYJKoZI hvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTkwMzE2MDkwMDM4 WjAvBgkqhkiG9w0BCQQxIgQgu747Zx6FPf4woOYFlDZvJPAvMeok/0ZRdD/WDHPN aCIweQYJKoZIhvcNAQkPMWwwajALBglghkgBZQMEASowCwYJYIZIAWUDBAEWMAsG CWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0DAgICAIAwDQYIKoZIhvcN AwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwDQYJKoZIhvcNAQEBBQAEgYCz vhp05pvQNr25On3965Z+JXk6auQV9tl1bxI39jxIPxykJgoVKIC5b6FIMnzpPzZA I66bK6Tx7dY5PTRcYImjkKgFpubNObwhFaNGeOyKh+W+o7Kic/Zy2nlWwGVMQ3ad fCDfp0iR46yzoL94pWXrt+2DSQ7QzMRWvKy0SvNdWw== -----END CMS----- -----BEGIN CMS----- MIIEegYJKoZIhvcNAQcCoIIEazCCBGcCAQExDTALBglghkgBZQMEAgEwCwYJKoZI hvcNAQcBoIIC1jCCAtIwggKPoAMCAQICCQCEbw8q6JYKTTALBglghkgBZQMEAwIw ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTAeFw0xODA3MDEwOTM1 MTRaFw0xODA3MzEwOTM1MTRaMCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBs ZS5jb20wggG2MIIBKwYHKoZIzjgEATCCAR4CgYEAu1pOSXz76spaDcSOsEx8vzAB +xC1LNppXIxeP/mQHim7ADlf5uNPAavPt1Ky7kkJHbdxj9sWXUG+BvgC1CSNoEkO 0b4A2OTkYdfgCjk8CSjNK4LgsLZcNDW+MMa4G7AooGAxTL+WbvMxMKmWly9eDODd VVN2M7S2UCKPlIkoDjcCFQDcpQZHCPm2jIkDaMNf3WJggezQxwKBgDKLgJAp/VlG YYflUdnJzcAWS04vg+FQaRIQhocrzaUJQ/ZfPCYtjCozt3gL9KNwFghXBklo082s Qwin52NgohB2fBKIOsvBPX1VU8oXmtQ4vIN1L6kmPZkeZvEkOJdVojHBJehU1CDh UDT+PEH3joy2s3N9AC1SE1UplbHVBsE5A4GEAAKBgH/LWxi51YZsuzDiIkXdqPAB +jiJqfccumYpG4m+nIbCaBDCMXxxKmfr/uQBcYFIbdAU4bK4WL7joHjCjXeA/DDz zjD3wqFSKax7xFKbBmAK0eC0UdwVlnx9qeJ9Ypduk58+CBWqQkyFJCIlf0aJFlKE y8BEvuPC6Hlu2nTc9SHeo1AwTjAdBgNVHQ4EFgQUTAOzcwRJKUUZaP/WO6LOlOLC YwEwHwYDVR0jBBgwFoAUTAOzcwRJKUUZaP/WO6LOlOLCYwEwDAYDVR0TBAUwAwEB /zALBglghkgBZQMEAwIDMAAwLQIVAKC36+0syuqwTPBd7MLJ7NBJS10XAhQRKGb0 d0Q8f19UOAr5ROp10HSxdTGCAWowggFmAgEBMC4wITEfMB0GCSqGSIb3DQEJARYQ dGVzdEBleGFtcGxlLmNvbQIJAIRvDyrolgpNMAsGCWCGSAFlAwQCAaCB5DAYBgkq hkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xOTAzMTYwOTAw MzhaMC8GCSqGSIb3DQEJBDEiBCC7vjtnHoU9/jCg5gWUNm8k8C8x6iT/RlF0P9YM c81oIjB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFlAwQBKjALBglghkgBZQMEARYw CwYJYIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqGSIb3DQMCAgIAgDANBggqhkiG 9w0DAgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIBKDALBglghkgBZQMEAwIEMDAu AhUAqTVaVNHUEv4tM84y/QLPWSr0cP0CFQCvlZDKBaa0qlBWE2NyJ574gyXqkQ== -----END CMS----- -----BEGIN CMS----- MIIDRwYJKoZIhvcNAQcCoIIDODCCAzQCAQExDTALBglghkgBZQMEAgEwCwYJKoZI hvcNAQcBoIIBjTCCAYkwggEvoAMCAQICCQCX+mbx0uA+ADAKBggqhkjOPQQDAjAh MR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMB4XDTE4MDcwMTA5MzUx NFoXDTE4MDczMTA5MzUxNFowITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxl LmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHYqvg1E3p4xXBUK+72zfa3M LmJIkfZDsYqRsZwRXJ7TzRxsbeVgBDVy3Zj6Y4ZSB/dK7jxs54KTECoDcXLvEASj UDBOMB0GA1UdDgQWBBRT2nMGMWO1FT6OJajOnO9gp1hHVzAfBgNVHSMEGDAWgBRT 2nMGMWO1FT6OJajOnO9gp1hHVzAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0gA MEUCIAvA93qcJRkeyRffr9IKzYQXkZE30qnCBzlEfmfUClagAiEA0GQKzKiwGTv6 uV1pwjprqyI7h0dObEESk3KMQRa+5zcxggGAMIIBfAIBATAuMCExHzAdBgkqhkiG 9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20CCQCX+mbx0uA+ADALBglghkgBZQMEAgGg geQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTkw MzE2MDkwMDM4WjAvBgkqhkiG9w0BCQQxIgQgu747Zx6FPf4woOYFlDZvJPAvMeok /0ZRdD/WDHPNaCIweQYJKoZIhvcNAQkPMWwwajALBglghkgBZQMEASowCwYJYIZI AWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0DAgICAIAw DQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwCgYIKoZIzj0E AwIERzBFAiEA0zBWegmlEC9Zp6Nql04cSiCD0ZdlFzecaGoF+xmctUICID+cT8s9 dF/iJdrrTKh4+UmuAXO+PMfVRXwjP1TFBq4z -----END CMS----- -----BEGIN CMS----- MIIEPQYJKoZIhvcNAQcCoIIELjCCBCoCAQExDTALBglghkgBZQMEAgEwCwYJKoZI hvcNAQcBoIICgjCCAn4wggIjoAMCAQICCQCgEjyokIqTbTAKBggqhkjOPQQDAjAh MR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMB4XDTE4MDcwMTA5MzUx NFoXDTE4MDczMTA5MzUxNFowITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxl LmNvbTCCAUswggEDBgcqhkjOPQIBMIH3AgEBMCwGByqGSM49AQECIQD/////AAAA AQAAAAAAAAAAAAAAAP///////////////zBbBCD/////AAAAAQAAAAAAAAAAAAAA AP///////////////AQgWsY12Ko6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsD FQDEnTYIhucEk2pmeOETnSa3gZ9+kARBBGsX0fLhLEJH+Lzm5WOkQPJ3A32BLesz oPShOUXYmMKWT+NC4v4af5uO5+tKfA+eFivOM1drMV7Oy7ZAaDe/UfUCIQD///// AAAAAP//////////vOb6racXnoTzucrC/GMlUQIBAQNCAASRj2SKQoEgjz6+KYQx zT4ayoZgTTCBYWY3EiaJl5ok0cqIU7SBaPdN+qTVczCMjUvrflk8wDmKmgdrVauL H/l0o1AwTjAdBgNVHQ4EFgQUgvJMdTkQVKStsiGY0/eY/NB/nHswHwYDVR0jBBgw FoAUgvJMdTkQVKStsiGY0/eY/NB/nHswDAYDVR0TBAUwAwEB/zAKBggqhkjOPQQD AgNJADBGAiEA2aHN4T0QP85J2+vz2Rmpk+DEJzwb8Fv9DGj4gwcNiScCIQDwUiXY FcmbsiZc8oQxVcMKHXelMQUbkPq12rSnAOJNaTGCAYEwggF9AgEBMC4wITEfMB0G CSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAKASPKiQipNtMAsGCWCGSAFl AwQCAaCB5DAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEP Fw0xOTAzMTYwOTAwMzhaMC8GCSqGSIb3DQEJBDEiBCC7vjtnHoU9/jCg5gWUNm8k 8C8x6iT/RlF0P9YMc81oIjB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFlAwQBKjAL BglghkgBZQMEARYwCwYJYIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqGSIb3DQMC AgIAgDANBggqhkiG9w0DAgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIBKDAKBggq hkjOPQQDAgRIMEYCIQDtHZXf8lH3LgaqQR6AiCXWWn1rs+76ilGdbZtWy3ZVtgIh APRXOwsrj/zkjQ4gSvCgi0swPjceDvNqayJ+zc0c5ecz -----END CMS----- -----BEGIN CMS----- MIIEOwYJKoZIhvcNAQcCoIIELDCCBCgCAQExDTALBglghkgBZQMEAgEwCwYJKoZI hvcNAQcBoIICFDCCAhAwggF5oAMCAQICCQD3DetZLCk3mzANBgkqhkiG9w0BAQsF ADAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMB4XDTE4MDcwMTA5 MzUxNFoXDTE4MDczMTA5MzUxNFowITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFt cGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtBG2kKWfYT1jUXmb DlrkD3Wfw0rKDjTdjjSswM2HggMtEbiutc+cxnoW+DaeP1SzSdY7NXlaqvzftCPL vzJNaRM4HpG/XLqIdub5hzisbrwN1/Q77zmUvr1ka7NaXKZDuuepORJsNh5lHkp2 2VR0O0pQ3zLNjX8IVAGkdpoE5iMCAwEAAaNQME4wHQYDVR0OBBYEFPyU0yv/vEPO p1kMDzLvtT6U+gYOMB8GA1UdIwQYMBaAFPyU0yv/vEPOp1kMDzLvtT6U+gYOMAwG A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEAn2yZT/WNupO34PxVdWU65X9q mCE4AtZKLbRa0iSkkEY961oqDiMVWiaN0sPVeV1GoNCz9J8lLKaEkR8b0F4KlJ0K 44V+5P0Hvb1UnKV2SsNxkmNbxwjO8Q+9aNjd4IqxAnSyQ45yMN4K5x1COJFXQETJ ApFWhLZxgA0hqnotQGcxggHtMIIB6QIBATAuMCExHzAdBgkqhkiG9w0BCQEWEHRl c3RAZXhhbXBsZS5jb20CCQD3DetZLCk3mzALBglghkgBZQMEAgGggeQwGAYJKoZI hvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTkwMzE2MDkwMDM4 WjAvBgkqhkiG9w0BCQQxIgQgu747Zx6FPf4woOYFlDZvJPAvMeok/0ZRdD/WDHPN aCIweQYJKoZIhvcNAQkPMWwwajALBglghkgBZQMEASowCwYJYIZIAWUDBAEWMAsG CWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0DAgICAIAwDQYIKoZIhvcN AwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwPQYJKoZIhvcNAQEKMDCgDTAL BglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMCAV4EgYBS HLzcxWJqmnUPO4IpwKEf5Xsh359SPjFzcJUMQcAI/NswyRKN85WRqYrWuXbqBRX/ d1dO7o4hZEcU9y8VvWo6sZCba+teSvUG8qYmu13KE/UXYVW1ZIWbNWRsDhxDmlaL PGIwcx501+iCuwogqFYvGzualDuMc+/ErbSQ6ZVN5Q== -----END CMS----- cryptostore-0.3.1.0/tests/files/cms-signed-data.pem0000644000000000000000000001637507346545000020362 0ustar0000000000000000-----BEGIN CMS----- MIAGCSqGSIb3DQEHAqCAMIACAQExDTALBglghkgBZQMEAgEwgAYJKoZIhvcNAQcB oIAkgAQOaGVsbG8sIHdvcmxkDQoAAAAAAACgggIUMIICEDCCAXmgAwIBAgIJAPcN 61ksKTebMA0GCSqGSIb3DQEBCwUAMCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhh bXBsZS5jb20wHhcNMTgwNzAxMDkzNTE0WhcNMTgwNzMxMDkzNTE0WjAhMR8wHQYJ KoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQC0EbaQpZ9hPWNReZsOWuQPdZ/DSsoONN2ONKzAzYeCAy0RuK61z5zG ehb4Np4/VLNJ1js1eVqq/N+0I8u/Mk1pEzgekb9cuoh25vmHOKxuvA3X9DvvOZS+ vWRrs1pcpkO656k5Emw2HmUeSnbZVHQ7SlDfMs2NfwhUAaR2mgTmIwIDAQABo1Aw TjAdBgNVHQ4EFgQU/JTTK/+8Q86nWQwPMu+1PpT6Bg4wHwYDVR0jBBgwFoAU/JTT K/+8Q86nWQwPMu+1PpT6Bg4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOB gQCfbJlP9Y26k7fg/FV1ZTrlf2qYITgC1kottFrSJKSQRj3rWioOIxVaJo3Sw9V5 XUag0LP0nyUspoSRHxvQXgqUnQrjhX7k/Qe9vVScpXZKw3GSY1vHCM7xD71o2N3g irECdLJDjnIw3grnHUI4kVdARMkCkVaEtnGADSGqei1AZzGCAb0wggG5AgEBMC4w ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAPcN61ksKTebMAsG CWCGSAFlAwQCAaCB5DAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3 DQEJBTEPFw0xODA3MjIwNjIyNTlaMC8GCSqGSIb3DQEJBDEiBCC7vjtnHoU9/jCg 5gWUNm8k8C8x6iT/RlF0P9YMc81oIjB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFl AwQBKjALBglghkgBZQMEARYwCwYJYIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqG SIb3DQMCAgIAgDANBggqhkiG9w0DAgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIB KDANBgkqhkiG9w0BAQEFAASBgGbOWcUKMOVsuSHVJyepwfaECpLKJTQH2VDpyVbS /CLsmwsGtRQJEIOAVV9OezHHvngtChaCyIuwYmaP17qeN0R7ZvthN5+WCX2DuNUJ ucSxEfivSx8zwjns7M3944jUbn4zE33ltk4bjWgryOIASKm8snLgftewhNOU2wKP Ar8JAAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHAqCAMIACAQExDTALBglghkgBZQMEAgEwgAYJKoZIhvcNAQcB oIAkgAQOaGVsbG8sIHdvcmxkDQoAAAAAAACgggLWMIIC0jCCAo+gAwIBAgIJAIRv DyrolgpNMAsGCWCGSAFlAwQDAjAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1w bGUuY29tMB4XDTE4MDcwMTA5MzUxNFoXDTE4MDczMTA5MzUxNFowITEfMB0GCSqG SIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTCCAbYwggErBgcqhkjOOAQBMIIBHgKB gQC7Wk5JfPvqyloNxI6wTHy/MAH7ELUs2mlcjF4/+ZAeKbsAOV/m408Bq8+3UrLu SQkdt3GP2xZdQb4G+ALUJI2gSQ7RvgDY5ORh1+AKOTwJKM0rguCwtlw0Nb4wxrgb sCigYDFMv5Zu8zEwqZaXL14M4N1VU3YztLZQIo+UiSgONwIVANylBkcI+baMiQNo w1/dYmCB7NDHAoGAMouAkCn9WUZhh+VR2cnNwBZLTi+D4VBpEhCGhyvNpQlD9l88 Ji2MKjO3eAv0o3AWCFcGSWjTzaxDCKfnY2CiEHZ8Eog6y8E9fVVTyhea1Di8g3Uv qSY9mR5m8SQ4l1WiMcEl6FTUIOFQNP48QfeOjLazc30ALVITVSmVsdUGwTkDgYQA AoGAf8tbGLnVhmy7MOIiRd2o8AH6OImp9xy6Zikbib6chsJoEMIxfHEqZ+v+5AFx gUht0BThsrhYvuOgeMKNd4D8MPPOMPfCoVIprHvEUpsGYArR4LRR3BWWfH2p4n1i l26Tnz4IFapCTIUkIiV/RokWUoTLwES+48LoeW7adNz1Id6jUDBOMB0GA1UdDgQW BBRMA7NzBEkpRRlo/9Y7os6U4sJjATAfBgNVHSMEGDAWgBRMA7NzBEkpRRlo/9Y7 os6U4sJjATAMBgNVHRMEBTADAQH/MAsGCWCGSAFlAwQDAgMwADAtAhUAoLfr7SzK 6rBM8F3swsns0ElLXRcCFBEoZvR3RDx/X1Q4CvlE6nXQdLF1MYIBaTCCAWUCAQEw LjAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tAgkAhG8PKuiWCk0w CwYJYIZIAWUDBAIBoIHkMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZI hvcNAQkFMQ8XDTE4MDcyMjA2MjI1OVowLwYJKoZIhvcNAQkEMSIEILu+O2cehT3+ MKDmBZQ2byTwLzHqJP9GUXQ/1gxzzWgiMHkGCSqGSIb3DQEJDzFsMGowCwYJYIZI AWUDBAEqMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYIKoZIhvcNAwcwDgYI KoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIHMA0GCCqGSIb3DQMC AgEoMAsGCWCGSAFlAwQDAgQvMC0CFGMQG4Ti+cPlCkXhPNChuLXMZbSCAhUAk/am O8zvARpcfg+Weq++PJLzOm8AAAAAAAA= -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHAqCAMIACAQExDTALBglghkgBZQMEAgEwgAYJKoZIhvcNAQcB oIAkgAQOaGVsbG8sIHdvcmxkDQoAAAAAAACgggGNMIIBiTCCAS+gAwIBAgIJAJf6 ZvHS4D4AMAoGCCqGSM49BAMCMCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBs ZS5jb20wHhcNMTgwNzAxMDkzNTE0WhcNMTgwNzMxMDkzNTE0WjAhMR8wHQYJKoZI hvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD QgAEdiq+DUTenjFcFQr7vbN9rcwuYkiR9kOxipGxnBFcntPNHGxt5WAENXLdmPpj hlIH90ruPGzngpMQKgNxcu8QBKNQME4wHQYDVR0OBBYEFFPacwYxY7UVPo4lqM6c 72CnWEdXMB8GA1UdIwQYMBaAFFPacwYxY7UVPo4lqM6c72CnWEdXMAwGA1UdEwQF MAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgC8D3epwlGR7JF9+v0grNhBeRkTfSqcIH OUR+Z9QKVqACIQDQZArMqLAZO/q5XWnCOmurIjuHR05sQRKTcoxBFr7nNzGCAX8w ggF7AgEBMC4wITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAJf6 ZvHS4D4AMAsGCWCGSAFlAwQCAaCB5DAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcB MBwGCSqGSIb3DQEJBTEPFw0xODA3MjIwNjIyNTlaMC8GCSqGSIb3DQEJBDEiBCC7 vjtnHoU9/jCg5gWUNm8k8C8x6iT/RlF0P9YMc81oIjB5BgkqhkiG9w0BCQ8xbDBq MAsGCWCGSAFlAwQBKjALBglghkgBZQMEARYwCwYJYIZIAWUDBAECMAoGCCqGSIb3 DQMHMA4GCCqGSIb3DQMCAgIAgDANBggqhkiG9w0DAgIBQDAHBgUrDgMCBzANBggq hkiG9w0DAgIBKDAKBggqhkjOPQQDAgRGMEQCIFnydUTsOcJuwn9+EAcsL1N7MxQD gBKPMKY0H0idZsb9AiBFuYfwgxWnedMjHXE0ZswL8Z0jmdQoQqRvOjlD0kcwuQAA AAAAAA== -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHAqCAMIACAQExDTALBglghkgBZQMEAgEwgAYJKoZIhvcNAQcB oIAkgAQOaGVsbG8sIHdvcmxkDQoAAAAAAACgggKCMIICfjCCAiOgAwIBAgIJAKAS PKiQipNtMAoGCCqGSM49BAMCMCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBs ZS5jb20wHhcNMTgwNzAxMDkzNTE0WhcNMTgwNzMxMDkzNTE0WjAhMR8wHQYJKoZI hvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMIIBSzCCAQMGByqGSM49AgEwgfcCAQEw LAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA////////////////MFsE IP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57PrvVV2 mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR 8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84z V2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8YyVR AgEBA0IABJGPZIpCgSCPPr4phDHNPhrKhmBNMIFhZjcSJomXmiTRyohTtIFo9036 pNVzMIyNS+t+WTzAOYqaB2tVq4sf+XSjUDBOMB0GA1UdDgQWBBSC8kx1ORBUpK2y IZjT95j80H+cezAfBgNVHSMEGDAWgBSC8kx1ORBUpK2yIZjT95j80H+cezAMBgNV HRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDZoc3hPRA/zknb6/PZGamT4MQn PBvwW/0MaPiDBw2JJwIhAPBSJdgVyZuyJlzyhDFVwwodd6UxBRuQ+rXatKcA4k1p MYIBfzCCAXsCAQEwLjAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29t AgkAoBI8qJCKk20wCwYJYIZIAWUDBAIBoIHkMBgGCSqGSIb3DQEJAzELBgkqhkiG 9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE4MDcyMjA2MjI1OVowLwYJKoZIhvcNAQkE MSIEILu+O2cehT3+MKDmBZQ2byTwLzHqJP9GUXQ/1gxzzWgiMHkGCSqGSIb3DQEJ DzFsMGowCwYJYIZIAWUDBAEqMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH MA0GCCqGSIb3DQMCAgEoMAoGCCqGSM49BAMCBEYwRAIgUNgm3ZqPzXnroKk7iuXt vKzEEcwUdHK6L4GJ98Qz2CkCIDUcs93FD13W3WuyGFS6r3Oj5LlDs4MsOZnDbnIo yva4AAAAAAAA -----END CMS----- -----BEGIN CMS----- MIAGCSqGSIb3DQEHAqCAMIACAQExDTALBglghkgBZQMEAgEwgAYJKoZIhvcNAQcB oIAkgAQOaGVsbG8sIHdvcmxkDQoAAAAAAACgggIUMIICEDCCAXmgAwIBAgIJAPcN 61ksKTebMA0GCSqGSIb3DQEBCwUAMCExHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhh bXBsZS5jb20wHhcNMTgwNzAxMDkzNTE0WhcNMTgwNzMxMDkzNTE0WjAhMR8wHQYJ KoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQC0EbaQpZ9hPWNReZsOWuQPdZ/DSsoONN2ONKzAzYeCAy0RuK61z5zG ehb4Np4/VLNJ1js1eVqq/N+0I8u/Mk1pEzgekb9cuoh25vmHOKxuvA3X9DvvOZS+ vWRrs1pcpkO656k5Emw2HmUeSnbZVHQ7SlDfMs2NfwhUAaR2mgTmIwIDAQABo1Aw TjAdBgNVHQ4EFgQU/JTTK/+8Q86nWQwPMu+1PpT6Bg4wHwYDVR0jBBgwFoAU/JTT K/+8Q86nWQwPMu+1PpT6Bg4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOB gQCfbJlP9Y26k7fg/FV1ZTrlf2qYITgC1kottFrSJKSQRj3rWioOIxVaJo3Sw9V5 XUag0LP0nyUspoSRHxvQXgqUnQrjhX7k/Qe9vVScpXZKw3GSY1vHCM7xD71o2N3g irECdLJDjnIw3grnHUI4kVdARMkCkVaEtnGADSGqei1AZzGCAe0wggHpAgEBMC4w ITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbQIJAPcN61ksKTebMAsG CWCGSAFlAwQCAaCB5DAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3 DQEJBTEPFw0xODA3MjIwNjIyNTlaMC8GCSqGSIb3DQEJBDEiBCC7vjtnHoU9/jCg 5gWUNm8k8C8x6iT/RlF0P9YMc81oIjB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFl AwQBKjALBglghkgBZQMEARYwCwYJYIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqG SIb3DQMCAgIAgDANBggqhkiG9w0DAgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIB KDA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3DQEBCDAL BglghkgBZQMEAgGiAwIBXgSBgCBmZlgPvc6GpULvkccID/ybILnVh1Zcu5DnhvOz isNXtcm3TW8xu9+rLps95FfNrb0akRVRdrHMdOlwwV/y6gl7P7c5lpcijQnIIFae 5j6YV7LDJNGpnssxkQyF+Kj3wTMdvf+0yChjCSQ9QFkNK/lUZTO9LhXc783xhAO5 7EQwAAAAAAAA -----END CMS----- cryptostore-0.3.1.0/tests/files/dsa-encrypted-pbes1.pem0000644000000000000000000001105007346545000021155 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIBcTAbBgkqhkiG9w0BBQMwDgQI/aS3q8Ny9UYCAggABIIBUFshzMyw/YNj9r0a 44vQzZtQ2Xc2aRqQnRJuERmPZiMIUrc41Ej/wGRMJAPItBZJkVPGCOrkgYmyyHK5 bsyIVoZfCUTfOU5J7rJVdzayQeE1cWjWpcBQVSEMH0k2GctKHOeGN8vzXjVq6hXh 4XchC/0n5EWVtlbTH2s2nuMSjUY9CQeaodIlW7cuAk5AE97OrQGWK+0BRrHZrbhw bjR2fuJVPrPUuUrsuZK7PyKrOpUB8s1GE/2UQ4taCa+eBZfbkD4C82e7kI6v6ZJx ECnIVhvA/2I2qic4D7ml7rIlp3Zizs7pXkeoWgTpWrGaUXxQr26jmGWDYJ8WiulW h5c9Wo4G3V7xUoYssQu29qHnrB7IQT2dbrL64JbaFjcOXbXlrJ99FOmrZhtXsCL7 vRipmnrumDaYMj61+petkln9ScRmhl2rP36/nGFIlwJxmJeUQw== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBcTAbBgkqhkiG9w0BBQowDgQIr3nft7PJIm4CAggABIIBUBSoegLJo8BpcE+5 3AAnl7cib9JD4g3wsnVKWc36+32uU4dg+cPgN6/E9ULRvKX9PM1U6MZwUb3M0QAs IuZ5UkkW1iNHmxuQoD2EZpBzTM0ykaDq8O/3dRdpmBNrRAW7tiPZxtffgySjzShA m/tSH/w2jydZswsP32ZDAgevPG317fHwMVeaI1Gz7DRPxRIRpwgy6HuovwK9N4+W jT7hNdvA4iybnFSiYGt36nHlaEjEmkayPAXTcLtW/p/4ctsYr1O2Uq24l2bkZZMH abyjm4BYrJV/gV91p/C+wggOCsXBBVF9Awf6YIXC6XF4C327/Ov3ORXJQh2C7ANO QGOSqCVZo6o1tlP62XKRmuDDiObl0TwuVG5cyQac/triWyPKtvAEinyv/OM4lCue 7az07xON9WnpwF3suDpZfx8aKlqNPRhJIce4mE2Wjp65H+5U9A== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBcDAcBgoqhkiG9w0BDAEBMA4ECMngjuURplazAgIIAASCAU77yI2EF+UXyyDN wp4oJRKrpXSeJsRLV9LzgUMVanmVSJNdkjAilQGE8refAAXzIcV/DKf7jmLgT6t6 34vyDu5MQTKX9Sq/35RZDgQt0epNRl8x9HkzJXbMwXpjxqN8St5fW3CG7klGyV4+ hIb4LfRXxHLajdhwJzLDo6hmE2TIYCMGZYWApObVMfms8qDN0ulYxPF0O7UtpNy8 sT5uvN1/CVUJmG2pfygbdZ/tBkTJLNzbt060EVXBIdUgAkohMq4v2Bm6dM+3FQMi abC6rLDlf/Yhleaa0nCG7GUpBDD77AIr6mJ67TYg+//vJa2WWwTc5DOk1+Ooz1NJ V1Fj7y3EmG9zBb1EboOBo59/VtWhpAwp73x9QidzZ+RhZqvFFHBuOE2TUxbGlZqO w6Cqg6hVz/dJkfbrjQ3I0HFPQPHJLTmmZbqMvuliv2h4g5YM -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBcDAcBgoqhkiG9w0BDAECMA4ECB2W/D5ZtLxUAgIIAASCAU46SZU3kLb1v26l +yAlWkhOypf3Bq5z2w/qy2eRsK827S3FvanOUrjG07VicYJc7wssCvbC61HNxyDT 4HCvx2tD1VeHtzUcP6/clLwb9ARVNtoA7oLlfloXpTa6WiMbXgYSP3p7CQCvfIX2 HYnihuFNoMjnZw08GHvy/jEVe7HuN7VSHJ/QSXsv/nIWWRdHZRaZYtLAjYwHH7iT z+0D02yiLjN9P5q5dtvUBnwBTrWaSyaYvO1zI++WtEDx22z9CXIh9v3kF5qyZIuO e4iI1dn2SN+uxzQPs3IPcamt7eKsp7HQYwwkh3TXPy1xWlF6MRvSkU+q20sgfVLQ pyHr5/Txb3EvcFnD1esZf0xFjwr5XcQFVSu625zGCKn2/0Z7BxtWaC7D1g3t2Jxw 5CdS3C7C11daouWHzVyJmdUc8WrbKFDy3/IZHgYWJ3jtNJgg -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBcjAcBgoqhkiG9w0BDAEDMA4ECLJqtxV8p51lAgIIAASCAVCiXfhPwBzmosBy p2uscyFJ3dTrGHFt/PDyjWfjj2KG1IwAPti/jUqRJkckaee1sims2AIfxfga7xlv wRgyNk6cNCHqjb5Khinog3O2N5FoJwLXnzmoPA+ilmTXcuv9i95mSYEzwR13kM8C 9CoUXQJCvWnuVAw6b/InGjCj5tic1MDWm6hufgydr9C9njhP9Qh2NkN8/iseiiWB 5preXZsXD9dyvQPH5qBu1aCnjLKYp5+bUl7UZ85mElvXOln5YW38DT1fX6XsT6b7 kn3wR5ol6PabdEOI7KNJh8T1PEIImrfo7T2rWmkPC3Gqmv6LeN1kbipy61QXqE69 rTp+dy/pCdtUIx9mC6lTwLf3Jy4tzOWObwHgTs1ikKvrI/di0vyd9e1xEY++Yxu/ ZJ16Ykpb9Z2H8xmRk3OecCVbSCcZ1wLzOhwdUbsyX71GSOnDA7Q= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBcjAcBgoqhkiG9w0BDAEEMA4ECAhz3Oo2dg4wAgIIAASCAVDYuvgJqqfDBcM5 guRg1jkoLUvVq8tmvGpWjbQMN4Z7JFnbeZcI7QQ4IqflLY83kHlE/G+418z9LYNV Xg/3HmvGjAQ47niW6hwDtcyKKk3P1iOi2ZTEAkt//Dvo0W9BT9spqsubEbvJRSw3 B4Q+Yi/hRRSsXhL/uSfVR4D6whGls08ryJr2cpQyZEOLXbGfZseSSt2l3T29mMas GWrG1aV86xU+P/fY7vLfKGUOtIrFD2WXWJTsJJaQZvCX/E7YmvcpGblq6CDnraFu DHTOtENK4Bx6ug1a+FIVPQGgjFDLZOkxLiVJUds88ATiaAuPwrUnPNUFNC6CX38P J8Rre1WNBKO7l8KVzIybUKG5+XNJQvmj0gGgf6Fm/736Y0rzJeiyBf8kSn9Z5QTv JczY6PbNppZLFuFTrZ772FtJ2oq6RTP1td7SmArW/YUCXxRaCBc= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBcjAcBgoqhkiG9w0BDAEFMA4ECFQ5zMHU0moJAgIIAASCAVCJFnOaptrH+ouw C9BvIjdOhy+eW5Ic3pZa8c8PxXruW5ehO83+nWgnPzXisMPW094Varoqe43mz7Sy PpHpWfNDqPq61cCci1Daxm1d0PHCTKhyW7leowGT23TIM19Xz7FlMR/oiSZkHqzH SNvOGPaajylKS9Tmle36MSGT0Qla/k74ILf2HWTouwZWi5mhTY6DpLziPZGQBly4 VMrWkBi8zYfYNfYtFWxTudHD7UmnLXh3nc71XEWt+1rwVJSE2TRur+GyV44g0Zwr 9EULlMGZWjprXhU7oqevMZgSqXsjwB2vs9r9473vLfAQfIu4hKfYF5+WBwAOzPb1 eqGNkrHMKEgUVMiTs5OrvWOVs2MUWKYufOdc4legc0Jd1WjfQSVSrQnAkvaNMCf7 kS7n6Ogc5DrzL38k2IB82VhdF9pZy1uAJvWaNRqOQMIRyZAkXyk= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBcjAcBgoqhkiG9w0BDAEGMA4ECM+XyPN3/xqgAgIIAASCAVAUYVbumKCpJl/k VhTOWoQX7LfUcfxoZTqfacml/itKo6GuNPjrtcPh1su6f55USVaQUiibkAx9LZbJ KpWtvMhSlQqumh8sJZ5XKOZsM4Nhuqp3ot8dd2VL0a7M6FlYFWf+hjU3Pr+WisoT 0uPdYz/PbUwluswR2E0fAIMA13VgcKY6hroNDKVC5PlWXJxsrm+5GqiWlDmntaHw TDiB1sjT3BmSvcImTf5BGkvP2+i5+VN1plmKSKlyF6vdBa1VjW6ghEr8kCn4cBjA TqcemSMfEaZ/lbqpB3klIcS1chxT8sEdFz/9sXBFI4cl61Yj7ZJ3IwvbzWLqELQ5 3c2TSYDxU+hrNau9VZkWwb7ZRALjHRMSk8MrKU35QalfSLl3DCEpNgF8fItmSVBB Vj0UfYskjTzHE5oWtTR0F3gB8G0R/I5Tru2c5Gn2ikbrRbC6gM4= -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/dsa-encrypted-pbkdf2.pem0000644000000000000000000001076307346545000021325 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIBoTBLBgkqhkiG9w0BBQ0wPjApBgkqhkiG9w0BBQwwHAQIcHjNGCgVdKECAggA MAwGCCqGSIb3DQIJBQAwEQYFKw4DAgcECLRvOz07zDcxBIIBUNoQ1qwaTP5N1d3g HVFC+XKnv43vfH+RhbJk6Rz3GVqTgNkRZ/giTXko0CDblPo/uQNnwkq3rvMMSssE gF2QvghHUEuPOY0PvRBgbrXXm/9ELC0H1B5lgbWNNuNZu7h8rpgxvxwLQbGi/PvX B2W0VBsCCOqs00uDP7BEWoVswanwfYNqqLZ2+q1/tk5RxtSGt0r6wvQkKP4s055h BllEqGU0/ZZbZ/af3bEbZszDPgrietyoL1SuUlPXAkgu9+geAWOnxvCTQf4lnvxo X6/RGyjmQDXprO9HvW1ttM2qNStqAkkwCuMgYjhZpnKMnswILEmfORIKnXD0pZ1E 2XZnxKpTgjWzwHmP7/GqLBH40+SvbvbFf4v3fIXbl861mc3u/rFCXZLmvhm5WS3L +kZZ0CgLHfvRjY40nBv0cTwZZwoQTJwbquZndb3yVhK0b+T/ew== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBpDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIInPsgUWW7g0CAggA MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECOFhwmqpMeP2BIIBUM2Q5Hd7I58d biaLO6o8eC1NIodvvkdwelWuJQFIIneaIH956tLangnmWoCc7Qr4s867J2+qkZMt E0tYJoRc0xl13hGHUvQqSX9Bmow/decn4/um9MY8Kkwu9aEwQFUHd3Eldn5ktw94 eLAYIMb7JtQDV2T1QiSW1oCGZj7HPzg5ZSjd4WRL/X5XYgpd84SaSaWHPy+Q+Fba eq7U84jHUgyrzo1pify+QrJAdRiWrgBlMgkw2Vvl5RFzToKjepTuwjX3rd8VUFpL TuKnrimXUrGcKVoO5SwjMpGAl8vyEcwx1dMeqdRdVrx/S4g9zZZoJ/R2Qz/M5o/F 9rdy1lSnMoBUUatW3uCPETMfenwFYBRkVyYDPgdhDmP1OzI8R34X6zurpVppy8dT +SR5H6PHTrtG7r8utZjhGtXAL0Lr5xaN8k3faMfyNbCAABME8Ex+ig== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBpTBPBgkqhkiG9w0BBQ0wQjApBgkqhkiG9w0BBQwwHAQInlrNCxahn94CAggA MAwGCCqGSIb3DQIJBQAwFQYJKoZIhvZ9B0IKBAjYjwYE1LBgjQSCAVC4RY1jocAq 2tw/ZiNbXAndRXAGSXHTRVKsN8ampNA9jptqvrWWK73HtRFb5nRwAF+eqfQJD+v0 h7pIXCoKoErJiTj23PPQc69pQDbeH1rKLCabR16lnR20L7wTz9m5ZXonq8BAOCNZ 5fpKk7sTK8aBRwDB61rys43PwdRaczqP49ZxnD04r5oztivMwcOHZ8k+vjWZVntf GiCWUgK1nfkIRNV2TpgzFaCzphxIOaQvI0oSWj4RDRSBp9QOYUalBkqhJrt7jSUz 2Egdxfh3v/vjEjDQ3mbnftGamO/8s5iQUWj0tlp/2e2a9XRDMWi1s0j0dN/z2Lel oqZEcgLbl1ejKH0+3UHpCTYL0rH9YnsT99gdyszljtztg91LVUMc4qmCLE8Yb/sq bWCuxqSqZqRCVkR7EFWKkzIoMLZraYMc1Zeqt1BWZUqLCU8oU8LyMDQ= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBrzBZBgkqhkiG9w0BBQ0wTDApBgkqhkiG9w0BBQwwHAQImzQMD2ZUPQ4CAggA MAwGCCqGSIb3DQIJBQAwHwYLKoMIjJpLPQEBAQIEEOjOVi0F+1g9Q9BzhIIUwdEE ggFQoNn6wN2rFabu2/HURiSNBVIMgWahYfWBTU1N9rKOg3QtI3hwlVJhi7a5UlPo RyLL4oSGpZz+JBgAmQEqr/PlcNiv3zvxbMrbZ7TcRzE4DwitbXRUXg6j4BhLs4ax wJRRGi0r8ZTl8/GGpOUJZj7VyLQmixNuJkkEXHpLuvXtobrecxb/g2ZWrMQx3goM bfAJbV49GrlszenHrd7IQ/Jtb5fG6qihri4St3j+hs2lkNHwVEfZR48i4cT0HDJM U8MeMjvFSpura3clcBNT6jhx/+cgoVfHZIw7xQl+GLUb0WTSID0qhq6ud3TH+qcM KpclX29qC4TOzVbVRCRA8NRYmmcaImgFdbcfiuvw0SKthcnx6dUmRktvX1lPmjdE 0uWYTJdrL7CxKmua6QgnGnYNhNmy8da70e1IeikY7u76/6z5edLIxKKm4/sImexL 3gfu -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBrDBWBgkqhkiG9w0BBQ0wSTAsBgkqhkiG9w0BBQwwHwQIm7wxCHZluCYCAggA AgEQMAwGCCqGSIb3DQIJBQAwGQYIKoZIhvcNAwIwDQIBOgQIsHuXH5aupi0EggFQ v/LaahBu1HMmBk+wnORTSL4AoVrPHBt+U3Af/9JXK/BLu18iDesLvAr3wGmBIe1l Ld6ilGag2faE33rDKzQv6EMpR3UypA3ACoDsqscakFfa8JKCLbeD8mgFOH3vVUuI PO/Vx6hSCAvW20FI1VFtzi+/tVgkneuHML1k9IFkbKNzWx3NZQKBMo4kuzmO+WGG iFWwuq29V/9UiyExm5DnA0FrctYbchtH1lwPb6aHPineEujYzuld1963N52pjtss es9oc/KGRhQtAjHVmH0gGWnQJR7n9i4TelBIDpBC3VPrUBccm2W2hA2HIH3WYRxW WsP/Nkg3UveiAE6/nXYvI1KZBIzTGeyvB9tnNcbT8nZ9GM4zkbtoO5Gva66AEzv7 6HC2zsOmF0fq0akz3cd5sMoRxg8JSMDPgYgsdJp6UYSQVI7xevFhCEBEy+0HVJLM -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBrTBXBgkqhkiG9w0BBQ0wSjAsBgkqhkiG9w0BBQwwHwQIupwrj1RegoQCAggA AgEFMAwGCCqGSIb3DQIJBQAwGgYIKoZIhvcNAwIwDgICAKAECAkkdbW6dpd0BIIB UJtbsPclMM59KZA5Y7YbF0Ys5d5ZSWnsJhQjWKL61FXgIBylub/sqlJCB3f+mSxC GqHZjeKPJMlI2/fwqYY8rrcQu8ex6AvRN/eJhjugcT3bJUs5o3UIwljvdZ0xCeJD qlPTjV0f1EAaGmIuLLGseIPZcmKrhzu7+L3+ti5+G/UeGU/AqE7glyIgYrlKfJF8 MMLdQ5L0K60cXBLO1PUAi4AYxxfclDdaASUcyE432CBxlGZN0yRO0zWM6BZ7uILd v8eZVYDJc6acWLRs2WtzsEZ4oxT0hAIArfAou7okdMbLBbfsFpAfbbyvqp/z06CT ZLlGySZPBWQc37d9FCSz4a9+6wCXqME49uozxxaFSkLQMWcxeTefrWyrAVD4QgIP g689TrBRAnAtdBIX84aM0sB4+rHJxr9hF694GKPm7Wz80OwVY3+3gYHKwzLLBbRu ng== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBrDBWBgkqhkiG9w0BBQ0wSTAsBgkqhkiG9w0BBQwwHwQIdH7jrafsUl0CAggA AgEIMAwGCCqGSIb3DQIJBQAwGQYIKoZIhvcNAwIwDQIBeAQI9jyutvOWsgoEggFQ sf8QI6BdcCfJmNklZu5NRLmK0GyU17V++XUaO0yPt92xlSC6h3bEPrPz3GxZrnOb ViLubKJLUqQUb+xZD9fHq0XRpRMnRSu906RAXR8FVreKwgz5071G5KsgJWwoOQhn +/6B3A5NjZbjwGkd971fGbOcOljLGqMfTv8KSlZoGTeKDLOV3Hk4H8QNY6BfU307 Sr39ETAozWoVVoQYCc0VmfA9lZEny8cvwRS46X0qj2HHUACn2qEI+8cOZkOUnv4r xL+/gJ474TjPX+Jd+KIndtWHyMPjRY6pRgdmsdWxjQqD+vEWR7sj96w+/x56M+mb hH3TQua0V7iAsoLzdKyob1+2naI7pqAaqxuRzVN7mATj+MN6t0NGMctiVy5LDb9C yJXUwLWN/8pgn2et7fbdjz6mWaUOgL6TIlG+OcPlp+sQUHwe+2rs88qAHJBjPYQW -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/dsa-encrypted-scrypt.pem0000644000000000000000000000364107346545000021476 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIBpTBPBgkqhkiG9w0BBQ0wQjAhBgkrBgEEAdpHBAswFAQINN5s8FaPzoICAkAA AgEIAgEBMB0GCWCGSAFlAwQBAgQQy5+msvCgFnxMEaD174O1ugSCAVDyvwNA1u9r Nj3DaCrlz0sE1fPAJJUCylvQLt6WGUvdsSAliFjv+K5GhtbNRbCUzXtCbWjkqMCY rwCXfp8CCvHFTTR8yMsuvyThrCfhRf9H1tMJaUDlAP9iVHcydTKeCgrIpkxNNNFB DEhQr6M1x7cOLCKsPB75Ap7v9Ks63p8UwhrilBjdIFnHJEEbzZsoFnY/TzMSTG3y pn9/cNhY1KVLWRr8j+6gQ/zFjAwqMyrI0ISoXim8rYkHEeJZGUXmYs0orLrxoqxe uSBkbr74rtHDdDaxv2ITFI5V210SY73mc/0C3DCy6ibp0flz16BsKd+EbOAExRKE x7zJSxJ1/gQiuP+FFKSN8s+cm5Xn2FdQE8D3h8csQ2HrTv5DBLdDL7xegq126WPE e1HlZPzI9F4N6EqbUGXsoYYFMeSQOMhVP2C+JRWYolVTtLJqAv0i8Ao= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBpTBPBgkqhkiG9w0BBQ0wQjAhBgkrBgEEAdpHBAswFAQI/FyWk+QpeTgCAkAA AgEIAgEBMB0GCWCGSAFlAwQBFgQQHSr6nDgm5G3mfzfwG0zeyQSCAVBZoK70Mv5l Bg3qHpI18jLTCgLqLu1cc3PwugzEqNa1ZjHSx/Kclqz4rtWar7omc+n403RGYsr3 uNnR5ENXabA7yCj4uQ492dKlFR2Qr8+I47PgMvjRpmqkczCCCe2JEixc3eRqzOK7 hTjAt03SW3OgZWL2VeZM+cF1CI2TphCfEt839APgXnH53BOMsuOGS+7gi80Z3HYV asxYTqOCW9b+CdQ/Jozt0s3LmuLElUdvRHBhvKtb8NzIePrCDhZSGGSGS43Px2JR c4yHUC37zNVWW24EvAe4WadVad2F9RS/1Titgxmu80Xd+rERxh7TbbRWecYjLQim T1XFmmqNHqScu8kypMEf0mElZx2M38uxn0VJy8wmkgoK4KbJuNvHRAOM+bcQwsJl GGxvH1HAt41oJ0FTSr71UV/nAD/tYJ7XuZEtZKYqKfQSN+JWYxdvkVk= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBpTBPBgkqhkiG9w0BBQ0wQjAhBgkrBgEEAdpHBAswFAQIToKQdJwvmYYCAkAA AgEIAgEBMB0GCWCGSAFlAwQBKgQQu9CT+JV6cKk50hxDchfwRQSCAVAwblK0RQIQ 1mRsFPmETlN0BpPuUhqmyPIR8plot/YYag2YomVMnS2fRpaBILtqv6yrJJq2VTgx TI4lsH9vsIrsDUjVc8Lzo+b/Bn3+90i7dKt1Wl1bOSTTyDt/FcAU1pUP/xBoaDTu 6in2XAvY5C2q2VVhvuJqhRkqxjYNCP+aof8qVijM2sw3qs49PwRw3H+V8SQ90GvK ZClddQdW0Chl9SH3aH7SKFyOfhiynI4MOauc1L19S6CXg6QfEOmi/EA5XVlzmkgg Ugpal8y7LE7q0Ua33Bxz/LDR6izRj/zaIMPXtahmQOzc7F8f9qTuyCVX56hl/KbW jerauH8Ls35UM60qtqknwIH9aN5rHU5fpP0i24qS/DscIDQRIJHzux7XfQO3EJlK QdowSSijvlrX2mz31rIuD4kmBsgdCn+x4AOimS6BSqMWswo5W/Mppds= -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/dsa-params.pem0000644000000000000000000000070707346545000017442 0ustar0000000000000000-----BEGIN DSA PARAMETERS----- MIIBHgKBgQC7Wk5JfPvqyloNxI6wTHy/MAH7ELUs2mlcjF4/+ZAeKbsAOV/m408B q8+3UrLuSQkdt3GP2xZdQb4G+ALUJI2gSQ7RvgDY5ORh1+AKOTwJKM0rguCwtlw0 Nb4wxrgbsCigYDFMv5Zu8zEwqZaXL14M4N1VU3YztLZQIo+UiSgONwIVANylBkcI +baMiQNow1/dYmCB7NDHAoGAMouAkCn9WUZhh+VR2cnNwBZLTi+D4VBpEhCGhyvN pQlD9l88Ji2MKjO3eAv0o3AWCFcGSWjTzaxDCKfnY2CiEHZ8Eog6y8E9fVVTyhea 1Di8g3UvqSY9mR5m8SQ4l1WiMcEl6FTUIOFQNP48QfeOjLazc30ALVITVSmVsdUG wTk= -----END DSA PARAMETERS----- cryptostore-0.3.1.0/tests/files/dsa-public.pem0000644000000000000000000000121607346545000017431 0ustar0000000000000000-----BEGIN PUBLIC KEY----- MIIBtjCCASsGByqGSM44BAEwggEeAoGBALtaTkl8++rKWg3EjrBMfL8wAfsQtSza aVyMXj/5kB4puwA5X+bjTwGrz7dSsu5JCR23cY/bFl1Bvgb4AtQkjaBJDtG+ANjk 5GHX4Ao5PAkozSuC4LC2XDQ1vjDGuBuwKKBgMUy/lm7zMTCplpcvXgzg3VVTdjO0 tlAij5SJKA43AhUA3KUGRwj5toyJA2jDX91iYIHs0McCgYAyi4CQKf1ZRmGH5VHZ yc3AFktOL4PhUGkSEIaHK82lCUP2XzwmLYwqM7d4C/SjcBYIVwZJaNPNrEMIp+dj YKIQdnwSiDrLwT19VVPKF5rUOLyDdS+pJj2ZHmbxJDiXVaIxwSXoVNQg4VA0/jxB 946MtrNzfQAtUhNVKZWx1QbBOQOBhAACgYB/y1sYudWGbLsw4iJF3ajwAfo4ian3 HLpmKRuJvpyGwmgQwjF8cSpn6/7kAXGBSG3QFOGyuFi+46B4wo13gPww884w98Kh Uimse8RSmwZgCtHgtFHcFZZ8fanifWKXbpOfPggVqkJMhSQiJX9GiRZShMvARL7j wuh5btp03PUh3g== -----END PUBLIC KEY----- cryptostore-0.3.1.0/tests/files/dsa-self-signed-cert.pem0000644000000000000000000000201607346545000021305 0ustar0000000000000000-----BEGIN CERTIFICATE----- MIIC0jCCAo+gAwIBAgIJAIRvDyrolgpNMAsGCWCGSAFlAwQDAjAhMR8wHQYJKoZI hvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMB4XDTE4MDcwMTA5MzUxNFoXDTE4MDcz MTA5MzUxNFowITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTCCAbYw ggErBgcqhkjOOAQBMIIBHgKBgQC7Wk5JfPvqyloNxI6wTHy/MAH7ELUs2mlcjF4/ +ZAeKbsAOV/m408Bq8+3UrLuSQkdt3GP2xZdQb4G+ALUJI2gSQ7RvgDY5ORh1+AK OTwJKM0rguCwtlw0Nb4wxrgbsCigYDFMv5Zu8zEwqZaXL14M4N1VU3YztLZQIo+U iSgONwIVANylBkcI+baMiQNow1/dYmCB7NDHAoGAMouAkCn9WUZhh+VR2cnNwBZL Ti+D4VBpEhCGhyvNpQlD9l88Ji2MKjO3eAv0o3AWCFcGSWjTzaxDCKfnY2CiEHZ8 Eog6y8E9fVVTyhea1Di8g3UvqSY9mR5m8SQ4l1WiMcEl6FTUIOFQNP48QfeOjLaz c30ALVITVSmVsdUGwTkDgYQAAoGAf8tbGLnVhmy7MOIiRd2o8AH6OImp9xy6Zikb ib6chsJoEMIxfHEqZ+v+5AFxgUht0BThsrhYvuOgeMKNd4D8MPPOMPfCoVIprHvE UpsGYArR4LRR3BWWfH2p4n1il26Tnz4IFapCTIUkIiV/RokWUoTLwES+48LoeW7a dNz1Id6jUDBOMB0GA1UdDgQWBBRMA7NzBEkpRRlo/9Y7os6U4sJjATAfBgNVHSME GDAWgBRMA7NzBEkpRRlo/9Y7os6U4sJjATAMBgNVHRMEBTADAQH/MAsGCWCGSAFl AwQDAgMwADAtAhUAoLfr7SzK6rBM8F3swsns0ElLXRcCFBEoZvR3RDx/X1Q4CvlE 6nXQdLF1 -----END CERTIFICATE----- cryptostore-0.3.1.0/tests/files/dsa-unencrypted-pkcs8.pem0000644000000000000000000000077507346545000021552 0ustar0000000000000000-----BEGIN PRIVATE KEY----- MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBALtaTkl8++rKWg3EjrBMfL8wAfsQ tSzaaVyMXj/5kB4puwA5X+bjTwGrz7dSsu5JCR23cY/bFl1Bvgb4AtQkjaBJDtG+ ANjk5GHX4Ao5PAkozSuC4LC2XDQ1vjDGuBuwKKBgMUy/lm7zMTCplpcvXgzg3VVT djO0tlAij5SJKA43AhUA3KUGRwj5toyJA2jDX91iYIHs0McCgYAyi4CQKf1ZRmGH 5VHZyc3AFktOL4PhUGkSEIaHK82lCUP2XzwmLYwqM7d4C/SjcBYIVwZJaNPNrEMI p+djYKIQdnwSiDrLwT19VVPKF5rUOLyDdS+pJj2ZHmbxJDiXVaIxwSXoVNQg4VA0 /jxB946MtrNzfQAtUhNVKZWx1QbBOQQWAhRhml7zu5ShPwMQujf9s3NuLE49pQ== -----END PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/dsa-unencrypted-trad.pem0000644000000000000000000000123407346545000021443 0ustar0000000000000000-----BEGIN DSA PRIVATE KEY----- MIIBugIBAAKBgQC7Wk5JfPvqyloNxI6wTHy/MAH7ELUs2mlcjF4/+ZAeKbsAOV/m 408Bq8+3UrLuSQkdt3GP2xZdQb4G+ALUJI2gSQ7RvgDY5ORh1+AKOTwJKM0rguCw tlw0Nb4wxrgbsCigYDFMv5Zu8zEwqZaXL14M4N1VU3YztLZQIo+UiSgONwIVANyl BkcI+baMiQNow1/dYmCB7NDHAoGAMouAkCn9WUZhh+VR2cnNwBZLTi+D4VBpEhCG hyvNpQlD9l88Ji2MKjO3eAv0o3AWCFcGSWjTzaxDCKfnY2CiEHZ8Eog6y8E9fVVT yhea1Di8g3UvqSY9mR5m8SQ4l1WiMcEl6FTUIOFQNP48QfeOjLazc30ALVITVSmV sdUGwTkCgYB/y1sYudWGbLsw4iJF3ajwAfo4ian3HLpmKRuJvpyGwmgQwjF8cSpn 6/7kAXGBSG3QFOGyuFi+46B4wo13gPww884w98KhUimse8RSmwZgCtHgtFHcFZZ8 fanifWKXbpOfPggVqkJMhSQiJX9GiRZShMvARL7jwuh5btp03PUh3gIUYZpe87uU oT8DELo3/bNzbixOPaU= -----END DSA PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ecdsa-epc-encrypted-pbes1.pem0000644000000000000000000001206007346545000022234 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIBoTAbBgkqhkiG9w0BBQMwDgQI5MTTa4Q3G9wCAggABIIBgPkvqzm83Jam+28T hCMbmBSmEJBexnqiWndSP9z/RJZ4MVQhj98K1hs3PnwAf14PxYhLtZ1hff678KBr /DQjE6jTErbZ+D1c2jAF2ZulG3PsjBsF0FIQw2Bf8P/RnzVUoqPoHpYW9BJZhcG6 jN4OhkzKX7XqSUBE8V+tbhwXGnTR7jbknQ3FGRrHSNiRTKaQn+EWIwsyg0LJgWGJ QXVN/fetsUgFeQUj3CMMd+BqmY7PE1E0v0zJ4A9yj1GL7QGilJ212k9almsyWwYA iNrTK4Ngo4BBFXQUmoAjmdBA2sxTyOwmL3FYN9ju2E8IAQg26l2dozj6VPOCQv2D /biVPYinmNQPrpq4psv2wZgo211XrMqPRFb11coz7OGZXUmmaeEzsc30lp4N4fa4 S3HbIvluwgTan68EANSZcYR/ry0MGoQjsbb2FoKMnuEpTXQLEAC2b9PYKv2+Bqg1 bsPJPRBFzPxiDTjyhkX05mY/8r20bfBoXERh2ENkNZMEkHhvgQ== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBoTAbBgkqhkiG9w0BBQowDgQIpbYR4hJkTcgCAggABIIBgMmPK83NuhSsNiqa jgw6o4vWyngy40F6wBiK0/ouAb9e0tCGK7/TCPq49qn4u5Q7ble/Ufl9p9nbL7+J HnQ0uiYq8aNYNIB1VtbJCrwBRz7lG05nwvbydT3uzsEIbgHCtHg+GpP2sPuipKxZ k8AYpOlT1etn0am6masjvdBWQlAdq534xfBHDCDwrcYbNASe20oQ6J5M7uJIKXza FVBJL7pvWAHuZbB9tIz2iz+wHrQKXdmhmJ/ePfoOnXWd8WGSgbSCLvgd0iRgQ9Yc 4mQOE7ZTv4koM2PtpH3qGpOW7hgFDEoWXouolQpXtGiQeBBTBWJHBDy2GSYgPUi3 Hj7ATyoCiP2j3iEFtnyhs+6okyOBhWjpKfNPQoiU9MhgJyna2n2jh3TU7c+cl1z8 eIo/5pX73alFLsyu2DSoJdt3gIyroqQHJ4n+eKSq1B6/CQLN1n2zUk1l2umnC/1X 8qQQMvOaE+Wgrv4puy9Nuh2BkwuXAirZJ2UcYwBrel5suC+jXA== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBnzAcBgoqhkiG9w0BDAEBMA4ECB2jmfJAz7EfAgIIAASCAX1FgUt+XM9DG4Ay 2yD/npOTZp1izQkniOT/3b1XqL0KMAZuYL92daHAgBM7hPO7sZGWh+FQBkX4eLNG Ak14idq9U2TCZmV0lIDKWR897DkxM9LW2YwAQxXzwH9frqo+OyUQNBero+F2Znc2 kEpjT85W68qpGI6XFXFRUTmZ+K+YEtGDtwvm/a5hV8CdGAg1NrkJEu9g1NeUEEg6 4PRLRv8IgPeNEIWJBhpw6WXgIjkhnf3GHGYEs9RqO041ZlRHE7LeRUY9T1NqcQ+s XEm0KM0NU5STJthfaqsv5TK2GUHgHBPex0Hwlht08b2mp2YZokBfxhgucUgWSeTg OntU6rmJtuOy8bvisyaR/G1em/F0L0toFeetcq16U3EG/ZrbJ6mW3tgaVrQwpoFg 6fwJbgi1rTGT5Mel6nphcMBMK+/9AOw7MO8pkn97ddImFc2tqK2e2L8GYjpSLEiG 0dK0Lk0m+kb1iiwwQ+KbgPbLBG+31jBHANL3jlewXd9oKFc= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBnzAcBgoqhkiG9w0BDAECMA4ECIulPRng61PVAgIIAASCAX2wES4a4zOo45Qz 6Lao4h6qkdtZeiJtNCWkmGoNsNb0GQi+HpOD71h/E2HLdpLxAV1RNbGeFV32j9Um m1iLRL/S+wM5/CorkV8lSqZd566kXUWo8dYU1aSOBwpktB1MAXBUaPvlM3NZQyVN Oj9ZTTV2/AOG2Ca5L1rX0nG5A69m50h0EHoH5MV5cKIoTHRfnOx4jUqSsfQgRI4X wo4esYVraC3L6Onzveb4Q7H5DCF+4AY/ziNRQRP91tvOseti291qZitGq6DY2t7s QOl0oLFU/obeG87RC4syLQRm/xLt6aXIAvHzy+V5h6QwPnZAtVpLyBAYLbVx06YX 1aV/nFw+F7U+9F9daujM9upr0/c/44JPwhTHUCMdPMkmXoF8RaSdQN0V4UHDMBnT t8ZXhjMxC/B5aZjDvyEnMtkKTllA7DTE9gU7SBALt7KaGX/dM7EpZbVs26VESwiL hT/IZxtZ8zjwMkF+ixOOOZR0eNf16TT+kYgU9k/yYPzYLuc= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBojAcBgoqhkiG9w0BDAEDMA4ECGcyMGdLvxlfAgIIAASCAYDFC/PBeI3Yl8m6 QQjW1KMrAralt6XHcZMncSBUc8Lm/Kq1AHntjXMqbph0IKVLiqsTJ6DfABXNnmuj vCDwF6VNGw1oJSAFXy61PKmBIQY305kDOvqjou+oxTdczun2wfAsPjLWksQ+nj4u 4VRsyMyuw+W3B9zqbDgc6vk0J8ps6VYQQsdngOjRHAeF6Xy89GHJ7jKEA8hXlizr 7QD7GnD6gc1of3qMFgZyTPOhvgLUuGHTSlrTYd4mo7bzyVMUWq1NHtz2TVeg1nUe KZLKgUNryL5oe5uw3gbflvkNSQOsbJsmp0QiM45Ont20QmWqtGtkig7pYDhltff7 VXomwNhCWAsyJl1EOrDQoegUGe9Yj2C4J7aL2SHQ5+molUAZUJfXo1DjyxF9E4BX kiAL2Jx5pQGmJgJhDoJOLc0Q2ZsHJdpHPgx4Ajzx68FzISi526+vdndLy0woULbM nuaBujaklBpqBR2KvvIYjkYURKE1mm03C4h9WEryPqLvHkhvPKk= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBojAcBgoqhkiG9w0BDAEEMA4ECDZitMOHFzavAgIIAASCAYDpF4pB0sPDmOKG /w8AWQ8/uq8F5tzhLw8xXOwfj6JIN9K+p6VJMkRVNMeLRWNW2d2AdgWRhhZuNpgO N0Jb5TfVVYOKWmuC+hfp8eyS1TY3ortUnXjEqQqKkzDxSzwEKkjTLyHGm8+h4g4O STWJtOW8mZkILSe18syFw4XuTpzcTmkXpirV+L9ggDR1zkl8KlrpTp8/9XGsUTWz Ifl/5O3fhqdTse3khgAZaYvPeWnsdGZVr/KAO8iSannaMC0yzwl5M2y4WtJ3sMgw bNMkLATiZScQgo1AQnelLIusxN9XZZPFhpjow13t9+02pG6jpvl58Apu0og75Y1i NQDProzjDNces9XLBEPUvzXFfcGW9DMrthabuu0b/zRTj1L0McApp9r+pKTVgkng e6QdHpMWBV7A0lmpXqwr3AzXGhRky5UNNLQTMZbP8jhTXkADsNgMJgwmrNyW4MzL EZ4kwPsPYlv+vLjeVsiqh4KOVqSC/khv3e0NOzMredePo2Of2GE= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBojAcBgoqhkiG9w0BDAEFMA4ECLnZQJKaSTr8AgIIAASCAYC6rYNwcVH3WG21 aEmBR1PrTqtstosJzDR6KxNLxu+tQdKBWxPGXJqhGViYzQw/3S6Us5BxisZBQrHc TS0B3Da2EvSwVPj05qRWRVGmmpM2ODZwQIqOGmMHUMroiGC4A1W5wcY5CFZxUT2W 1Jfif0uxQJm7bVN+ULJEe32z4hSPj17p7JMbtQ0JbSvoJ+oIxog+EpjqH3/OWMJG UdxkyZlfpBx9l8EmNctGoCnz8ZU7BPXtBshC6zMwygaN1vAF965YtX4+qTpwwcxX yhANICx/3OYxcKUwmO6go0SaVDzkvuuKyx9BcLPwk9BaFklrdwcwQsv8FO80o3vk FUtk/anXILg5tMj74xIaUL8w3h9rg8K5G3TXntOyRq53bAO+GF0mUQVSB6hTE1J2 9hJFDUkvbsW0EixgWI64FKkorZkPyznP6js76GCuDzM9sHN8ywWsnmeK9kuGyDor a/2AuFuVa4rDZQ8aDymEdD/bL/1f9WYViblqzkgBnmTdXzv8RUM= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBojAcBgoqhkiG9w0BDAEGMA4ECK7Z49fQfS7TAgIIAASCAYBSEjWSOqI25pHK KmoozeWVJ4+WOwjxEXjuuDkEHOzbEaGrtYF9z66EBurZ9rJujpxfgMRtt8P2WyMW eK5JXHvlgoE1PFGjqmvuTSOmUp4ZUxMrMh9gFb3KaaaSq/AOQj2sZmGC+OqE8U9L yLO7HGyOtIc1UnzegINaC9TNj1/D4JTy1XgYm1S0xcgoxKZKIkhwHpQYRwByvXWM +wS+fdBp3a4UEKxUlgHsA6H35Lmu7epYlQqvywCj16Mpzkv7jquc1TLY+izuiCee d8yKGX30DN+lh4svbmD2oZPuB0V26wMzhOCx2x0WbJibBVI+NBqipy8BH11w7KIt hVTArXB9Unx0y97m7ut8LBqD7ogxqQxXzuIFYibMh6cm8d9F1KSZzEjHCQ9tZL93 eNKenZIFoLOkCcuD4RJfejW8zzPs6ZKKXpF2vW2ahqkbZfqTaRCu1iq9VETSMzam WannQc1uCzk1iTzTUrsWZ9ULtGeU7Yp3fvW7dpQB4AtAqi+wBPY= -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ecdsa-epc-encrypted-pbkdf2.pem0000644000000000000000000001167207346545000022402 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIB0TBLBgkqhkiG9w0BBQ0wPjApBgkqhkiG9w0BBQwwHAQIaXF1FSWH8FgCAggA MAwGCCqGSIb3DQIJBQAwEQYFKw4DAgcECEkew8xuyitxBIIBgAdLhNAUj7Bpglrd cbXUprOLFwtnPu/WJ5VQw5JuZPoIxxyq55g2jmtE1rK+25YZET9Pzyf8L7fkG1dh Qhi27AMcefNvbpRncwKQQYwU+C4kJ9PV6V/dvCqkfNB5ea0pbozI9zZ+ts1n7JpW szP9N8d51I7n/HIdpgPzxiV0eD0ZLjkUoxoRIi7EOVqXGpOt4mGkOW/mRgTD8wv7 koZSWM1hTw2h1hBvPPdWQih9i3ixx0kF5l4ZASjibnKWJZ+WW3C4kTK6xYGQWwZy fdOYiv0jFClRsPqHKtIr7Eg8TOtQb73rny9hQghchLWbTRuZDzljlV3QA6Hn4Tz0 pM7GfCrJHISkiWj8VXtKm6xSDKF6kyPUFN6MCd35IALnuRdTTGFua12nJye+R7lV lc9RJOlI2503csKTQK2uGRKRMt2m7uaRqNy8+B9+s0btN08oxrs7/Ui51xcUZ+QZ t1fDmyH9ym3KPeLBui39mDGXvyjNM3kKcWOFwEXdCYURHWMqVA== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIB1DBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQI/fA7dpDtXHgCAggA MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECBsyIBlhZP2PBIIBgLBTH21BBWz6 XWVouzSpVJ+XkekRTPrcK3pNBa/1sGCej6CTWr59cdcOr99DZ5RagHp28Udee/n4 WeOsyb0dfbUL9hjgM+rzpo9yNndwVvuRhdy7rpYDqcYkhSo+2bLIEgsItMnYcwbP x6XsLrv+ffxZlVIlRlhZUf6bGhgsI0gg3AIXnmTYQ1aX5OjZYoNgGUoOauL2d+xT n6z3IVfHlc5wFq10U73J1arv2vwsfM8PW0twnPeEjRK2WR3JQ+fKBoz+irESQuQq PFjKcWGTw7oBYpO4Hi3uKB25GzFNWLh9W5dqQ3gt+L9x/gbTlL6NWuG73CvH+cVX SkjFbncSbSbLA51HDJPEtipCsrZWKeWUK89xaKAvaIdsvi4rDJPI5CRCNpiWjdyy stkzjrhD43LLaX8UBwQzNXNm+dc/Ku1ZirWW6gn/0vZ2i6ioe618H2mAIqPmCFIb mgNIHxBhUwyYryiGHtxFDjjs7hK/EuinWi/RbFLlJb6EviF8cNPrvw== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIB1TBPBgkqhkiG9w0BBQ0wQjApBgkqhkiG9w0BBQwwHAQIbZbOKhH2r3QCAggA MAwGCCqGSIb3DQIJBQAwFQYJKoZIhvZ9B0IKBAhhyYd5c9VWlASCAYCLhBDXCXyw dSdrU/7zCYpT2c9wlSV2xXQReDruSOO7Z6E3PVSf0mAREzhk97kXCPGSQMqZqy5n GmxcGT933gvGwIsKpTeCtsDwiuxxD/HrbaehRSpXGTKI1SaVeZpKtdbvc4MPcVMu 26BI7EXRwDbmJbCJkg6oR1xSuEvbIewfq6Yy43vGrUK+pnSmaLg0bB7PnHuojb1/ KGfMZBzB1eavCwWz7htrVj+e1D2jKr42aVDLCMt6ROqb32y4dNIpMI55iiE5V+Rd FsSfrqFkYpvzuo216S98d1/YUwZ4SG/ooZC8yzbZ+3ZChMswBzs+HeFRBBI94RNY t8cW4cgw1tbzhPfckcHg+Mruo/IKfL/9xDdd0XLQ4ArX91fOOu8O5SfoF69uVj76 vLwao/z0HpqTVhsgbpseWol5k2Dlsmc43O8x1AdKE+Ua5eHgSbEweDzqSZOg4CwF CIt0wqx9EQgxWAfpTATv4pGu3/lG4POZwfauvHdb1fdIG6oiOhUyi7o= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIB3zBZBgkqhkiG9w0BBQ0wTDApBgkqhkiG9w0BBQwwHAQI7J2iZ7SSLdwCAggA MAwGCCqGSIb3DQIJBQAwHwYLKoMIjJpLPQEBAQIEEO87ALh2iTMdF6gfPDTAr/0E ggGAIH2qibHW4uIFdj3hmTTLaWXnKDtZiv5xA9HOvTcKgEx+9sxqMkZcHaTpGBq/ AgnktUJjmfNItwoABC5iWUWkhBFBtCxtiT3TcEdQpmvHDrzD8LuujScPRq+rcjIz u4+QhU0ZRKB6rKvfa6a3TkseH4QMRjwsVqt/vbBHhpqWBBpgc0qrK5iH6ioNgH9r sW0vemwY2iklPRgwpILAcFYx7GTfmgZ5ETqKvjXD/K4JZ1c9B+jL/e5Bq3oTXJbx mX4u47F0BcqXfax9Hg7YMuVtA633+zW+cTNjv3PrsnhPRcpLQ0JAMauh7bu1oLoI 9taZ0mwOMt1SZv8J+vR3i4t6TQ1F/h73gtZB428islJKpRS3U6v1aPlLZcfbN9JR cN2FdArs0X2hK0zwN7uOJJZxSegONq1wctEsXB4E8T1q/r3ojFKuwvO2mwkrLRgh oDseVijnW2R1m3USUdmaaqxeykLe0CS3beybFss4QbX4F/U/x17z9dqCLzoblH5D Pb2c -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIB3DBWBgkqhkiG9w0BBQ0wSTAsBgkqhkiG9w0BBQwwHwQIC6ZTCRU+rCsCAggA AgEQMAwGCCqGSIb3DQIJBQAwGQYIKoZIhvcNAwIwDQIBOgQIoFMVJ3EE/O4EggGA uA8nT1iW9fbvxFCXvy2myN9mwQyL8rnfLgbDhYZks+FyZm5tsDLbgw/d+ZhonzOM +PcVpwmcbegT6APDWAZjXvru6gpEwfxFzBjr8uoaKFdf6wEKbF3lTauxsgJjZT5X uykw5OBGnV3yv2KBX/wumL2g4xiHKbMpOJ7sC4OTs7r6m+uMjimHKlNIbJJMUfq3 V9afDbAz/epyoe96MqFGo0HyA4FsR5D9vKGqZFp3wMXpRFOSJIV3jGzaysVQkOXA yWRgUM0W1hL039hNteilCy4dMd7JqzFeksNz2wgVoLdUNu41Bvvv/NrAi+WG09Tt a82kRgJzB9zeVA6ZpYe+Xy8JpSjvXaVerTblODxVymBKT0cQofMRQjZsalLdWcy7 4GrpcpHNYLJ+hvzNLqHeWUBo3P79Chl7FZmFNX9ihdenjb/doTKB/eH2je+x3w8x xmt7CfeCpcR8EJRDb0GRL7yAcnmtBr2JJa30h1WeR5VeZJZ5chaXYsPBqv5HNomr -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIB3TBXBgkqhkiG9w0BBQ0wSjAsBgkqhkiG9w0BBQwwHwQI0g6+CtM4m9MCAggA AgEFMAwGCCqGSIb3DQIJBQAwGgYIKoZIhvcNAwIwDgICAKAECMcTOOizSU7oBIIB gJegyhG+XB4/LH/gr+OjDdC5aiht53g6pdhZ62fkmIf0zEI0ACO3K6zRhaF896HO KuQU85Nds3Oy4fMci4Q6XjZw2Sebxjw873HW8rHgXqlKanqixx1b9eDXJ+GeApqC oyHqxJeBDpWTo1T4SJjAIhITqn1AQQoKI/FWvjwMq4gD0536N7ln3O8omOoyV9i5 byqgxNLLZ6Ucues8ElcRW4rza/wKHvCMmESs8zDXyW74ax6ZMPGZ0ns5HDR0mVuk dMZ8vqKQDDuanDcKh728iMIevqFvagKdQI3GpWdr0F4o9JgZqLOk7dcnw/1Ao7i2 onBCk8+exCkyFY0zwXquzZEWongrOzKeyNoLdAYNe1ST/q/Kyr9pxxKpIPTEDU5Z 8Xh9qd+pSjEumqIQAVC2a53FstPJOKHVPjR7NaUN+9b7FK4MrhtW2itsMdI4Dtj6 BjxAqBzW0l8QaJHhr0JHqzvEPDZaiFC2jCjFRSwfOAvb7vOo//gMyJqqBIj3Dms5 2g== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIB3DBWBgkqhkiG9w0BBQ0wSTAsBgkqhkiG9w0BBQwwHwQItKps3ADDI0MCAggA AgEIMAwGCCqGSIb3DQIJBQAwGQYIKoZIhvcNAwIwDQIBeAQIhgAaNSOe6zcEggGA P/Namgvp1HsSCKYgggEIqjXcvE7vIcDcEs/YyN/dklLfn3QkngE7Rzx7zx10ZFMG E9OkfDzg3VWAJ6vzTAsrGb7h9sKRRtGXMxzM8eL6Umq5IADc5lvD0UYCPLBFGWp7 XFkFEWmZa2o4/abfKFnQVI8C8XTvE/LDNWmCmwpO3TBs9c94fl+Ra16BIVXMq+Ko OPzsQUDyIFvoAGbnrJQzehN7r6mW7usaiJdcqTvbklBpzo99RrgawIT3A6MGfYFb TLiDkA4cliUNWuoaOU7MRjQB5n249K8cuvD5qcgpEXiK2SZsZMTuU/zmGWA2ps8U FKD+sKHi8iU053HDBFUKRYZ8detecUOjGABcJvJWfWDNhKX0KcvK0RXYgVXXaS7q wVOtxYoITE8GkEG8DlCvF2UjHD8GZ7/JeFYm59E56ge9X/+pl96J2gZftN4RLgQ2 uecWdCDjKF0nJmFgstlHZ8VIVXplzzjIO4zyQ9J4QqpOENcXev6BLQaleR9vB/af -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ecdsa-epc-encrypted-scrypt.pem0000644000000000000000000000414407346545000022552 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIB1TBPBgkqhkiG9w0BBQ0wQjAhBgkrBgEEAdpHBAswFAQIJXpAnkCfm7ECAkAA AgEIAgEBMB0GCWCGSAFlAwQBAgQQeUbkFh7HD9nug87uhKnZ0gSCAYAerhWsm8dI DSaF7A+iBX106H/qjICoREVHN/a56FhO5HwWBGdIgfqv4i1R/6Uv4eAXWog5pQUb MfRRHNFlejqMik04TPx4kzcsmbToePuPtSJiyDW30p/zlke/bTXYVQXyTVSgzqsX O2HgKyOj5HrTCzZqM1OKS6YYlXRIsafgjJLlZDC/FybF/R1s/0kCugHTLqEDpHXx A0gcmvhox7vCScAh4616ay9n+R9eDfVoHEPKbRvcXztB+uifJtA0D6MtdFk/CSYi PIHjKcP4z/qe46mjJ9PyU/eOCZR+0ppowMwLSKTzPl+acDq+asCiQNoqZWMNUSOB F2jykkH4fFo1cKXkufIg3LkN4R90oHAK/9/4Vo4SxO+imiNfiEc1ktjedLrF0DSe 6zxFFe1KI45wMC5nBxQfDxiagYN29JZjbb8Up7gs37qTWpSEOeAxvTdTru+u6CaS zug8ow4MhEnimCy6q0cnq0xHiF719UiPW/xFRiZyTXTyp68JDSxoyz0= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIB1TBPBgkqhkiG9w0BBQ0wQjAhBgkrBgEEAdpHBAswFAQIB7B9+qlAXBYCAkAA AgEIAgEBMB0GCWCGSAFlAwQBFgQQ/Sn/EiqSFcj4ea3YHieu1QSCAYD3at0cyQ0l gp9S9MqBUEkHef6drW8CPf/oTnzfEOomtp3mXtwU4trzImpELFGlORl+gNZ9KUoF YixD62N1v4MhE9Ff47pN9lx2IYiLuekJaHqypRnrh7qU3V2KsrcqMcyNUIMyssLo CODMNxfiqbBAsbVcKnfxq/KBenT1Y/AiaAq6iPGRxora1GccuCSurePV4DbWOkRt sz81u1yIX9kzn3xVj/O6IubkDet7uFeFSro6MdPM1TlRMRxavXuCpO7yGEHC/Y1x 4Xq4J/wqrg25kqrntbkomjTgf02H2UoNhHIOgDZCDLTYJPCllcJOU5hjLaOJYD9x 743nxwYs4BNqmu7R+2WW4KMDTpfGnwuY5uhcqHBFPLNSNh0niZivzO0lV+AHAxKp BqAZE3TA9VQTayRFgp/XSd2RAntld9HDQkU3LBsKzmhnBF3xamLuCwtrm5a6wv4u bKW8LpgPOxWFMiLmcDOsjuhI/p8DqMzxexkBf3V/6P0ZGpcyI0X8Lok= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIB1TBPBgkqhkiG9w0BBQ0wQjAhBgkrBgEEAdpHBAswFAQIYz9Ct1ZSF3cCAkAA AgEIAgEBMB0GCWCGSAFlAwQBKgQQAvCaphXko8zb/53P2CmB+wSCAYAMCgKW+nkE BAxYuyXOc0IsTZMNh7gvS6coSNo/ukviJS5XNFH8iteaF9N/4y2zUo2Z1Fk2L9MY XPfZ0wJK1C9MQgEZrJu71d6duhqIiJPoiFM0L7czt//agaPRyblyWSOxhAAZNJeB xA0kXD1De1hatge80Pfw6C9uGJok8zwl3/N8vn0TdompMFSh3kTVwgBVwRwWzq1+ erf9Jg9xL45gVp26PJszHZzfyQCZWOC3a/sivaIeNlu41j+wpHy8gyd2R7HeEAyP C/ALAs8aoIGHS+ug9JzmeEPQNQ1g6XDvDFwmL4EmVISrTP1h3eauPYUQXmoCbgwD jKJDZCGVL08MAyb3QX6ceGJmeEJ8oDZURveys7A+j95pw27wBISWEzuXC4dhG82C uYSRm9RiWepdyE5Mj4aBr4z4c5keBsB8ekD9D5tUjbLMWt+ZC5RYGtNyv9bClKFI Jtwr1+abNauB26AoBzinCmMbaAyRr/ENKEPhWJuq3OozvIewW5RJbAk= -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ecdsa-epc-params.pem0000644000000000000000000000062007346545000020511 0ustar0000000000000000-----BEGIN EC PARAMETERS----- MIH3AgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP////////// /////zBbBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6 k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsDFQDEnTYIhucEk2pmeOETnSa3gZ9+ kARBBGsX0fLhLEJH+Lzm5WOkQPJ3A32BLeszoPShOUXYmMKWT+NC4v4af5uO5+tK fA+eFivOM1drMV7Oy7ZAaDe/UfUCIQD/////AAAAAP//////////vOb6racXnoTz ucrC/GMlUQIBAQ== -----END EC PARAMETERS----- cryptostore-0.3.1.0/tests/files/ecdsa-epc-self-signed-cert.pem0000644000000000000000000000163407346545000022367 0ustar0000000000000000-----BEGIN CERTIFICATE----- MIICfjCCAiOgAwIBAgIJAKASPKiQipNtMAoGCCqGSM49BAMCMCExHzAdBgkqhkiG 9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wHhcNMTgwNzAxMDkzNTE0WhcNMTgwNzMx MDkzNTE0WjAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMIIBSzCC AQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAA AAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA//////////// ///8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wST amZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP 40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////// //+85vqtpxeehPO5ysL8YyVRAgEBA0IABJGPZIpCgSCPPr4phDHNPhrKhmBNMIFh ZjcSJomXmiTRyohTtIFo9036pNVzMIyNS+t+WTzAOYqaB2tVq4sf+XSjUDBOMB0G A1UdDgQWBBSC8kx1ORBUpK2yIZjT95j80H+cezAfBgNVHSMEGDAWgBSC8kx1ORBU pK2yIZjT95j80H+cezAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDZ oc3hPRA/zknb6/PZGamT4MQnPBvwW/0MaPiDBw2JJwIhAPBSJdgVyZuyJlzyhDFV wwodd6UxBRuQ+rXatKcA4k1p -----END CERTIFICATE----- cryptostore-0.3.1.0/tests/files/ecdsa-epc-unencrypted-pkcs8.pem0000644000000000000000000000107207346545000022616 0ustar0000000000000000-----BEGIN PRIVATE KEY----- MIIBeQIBADCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAAB AAAAAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA ///////////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMV AMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg 9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8A AAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBBG0wawIBAQQg7AVNdkUlBnl+ PDsD3TPNSRxJFBDp3BzrGfKxUQee/uChRANCAASRj2SKQoEgjz6+KYQxzT4ayoZg TTCBYWY3EiaJl5ok0cqIU7SBaPdN+qTVczCMjUvrflk8wDmKmgdrVauLH/l0 -----END PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ecdsa-epc-unencrypted-trad.pem0000644000000000000000000000105407346545000022520 0ustar0000000000000000-----BEGIN EC PRIVATE KEY----- MIIBaAIBAQQg7AVNdkUlBnl+PDsD3TPNSRxJFBDp3BzrGfKxUQee/uCggfowgfcC AQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA//////////////// MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr vVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W K84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8 YyVRAgEBoUQDQgAEkY9kikKBII8+vimEMc0+GsqGYE0wgWFmNxImiZeaJNHKiFO0 gWj3Tfqk1XMwjI1L635ZPMA5ipoHa1Wrix/5dA== -----END EC PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ecdsa-p256-encrypted-pbes1.pem0000644000000000000000000000474007346545000022167 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIGwMBsGCSqGSIb3DQEFAzAOBAjX1Gfd0N4/lwICCAAEgZDAmo+X7o6E2jHihQfA wJhosfs/fOgvWXCSUFHJM6dDgvn8EVd8pElw1NUktV5cBIcL4HZpTmiZaMpDIXNj L9EkLEszXMY1wc4qLixGlsOpB5/KCBAX++w3Ur/vmzn5Zxh0vVjpjxNoaKjoTZH6 YE6fbFvp14vnKg6Uexld7k3efJY0PCMStcust6bLWSWikmU= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGwMBsGCSqGSIb3DQEFCjAOBAip8M8cWxEHeAICCAAEgZBJiHgjgH+b7gnFJreI iWOhI2sIDoiApQXji9QeyOsaWWhygR5sVKL4gkyzQcicPuz/OVYWQPGuMr2Qdvxr SuVjMmEBBh/sS0mWimxyrbnyZfwY7ZHMd0wWEBDni1KL9vIVSPWLhwfHvEFgdHlV UnfpWGUoEa2zjpGSCKOy/kaKnrQYeyKUdPaZjEvPU6aJidM= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGrMBwGCiqGSIb3DQEMAQEwDgQISqJaePRS6sMCAggABIGKnZo85GQkubGmIL0f 4RzIu9kERwTSgvnjH7gfW9ZvW15F2GruSyIRiuk1FhsHQhb/H8njlD2qkrYI3f1/ b3g5L5r5g+D/9C6C2ArbO3uZpvQor0pUyuKlESYd4E0LjveTKmCGW+xQRlmjwWZ8 XRMb+KakbQ7TL1lGLew9P3CIDAj7TxjTLSLwBa++ -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGrMBwGCiqGSIb3DQEMAQIwDgQIKUAgsPo+gu4CAggABIGK4j8mtUNzJm88CGuz NZbdzJpq+A/jHUKjJaTNhN8pUW2n/XeGmozPhRSQzzRHPMLoXUMUYw02ttJVVOTH seTcRzy1EQwTTmVe1MqL2FCffUCYD+bO5h9rO1AYC/hX3vr9+/O9KCj9pgTlG950 nQjb5f9wsE8BpMMf5z4e76fyoywdjOON7DOrtRoQ -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGxMBwGCiqGSIb3DQEMAQMwDgQIcndWv6ERzNcCAggABIGQDiCUJfL0YnPSV7xA Ke/bOMRlidthv0nRzQxzqaK/YkNPUQQ6d1RRTigXT/k4yBz9DH6q4sMpnjf3MyCw YFSXcQXZLnuq8zwjo5PoFyHb0U6QTdgd+IsegqupmyvzXOvLPcZH3/iRwNXqABip h5E8wPBSzobu8QztTZ/SOBnbyY3ys4QZckM60zLRWabE+IJ9 -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGxMBwGCiqGSIb3DQEMAQQwDgQI+DkAP5uNPwMCAggABIGQ/eMzhfa98PWmAzqc +1ti4VrxmHMwzdIGygpVcN8WhBbWN2mChFXE4ZGJIJYmpJyqS23aTIkRTElL0GuB WxcU/3uQ0CwdLtgHooPhGHkYnbHw8LwblnX7ECdt907KrRnqNHJ3BIFakNfvmbdN LncPFRdoJ3AMd3maXVvTyE7j5JF8dQGDQ6+iknmvd8YQHslt -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGxMBwGCiqGSIb3DQEMAQUwDgQIPxLQFIF8BHoCAggABIGQWAqlUpSLKexDJqz/ 3CHUsHnN0wtPxfe9DeDOB6Akl3I15HztsMh1jr3yvyV6yHCBe1VY77Wp7CTb3eAB f61rsMb3iFvgwN7ba87qnpg4+97oxU3UpEqpiIxu82NZzModHtqXcHwZ3RT0rc/f m3skEYWr/kjZaqCG3Qy08gdC8ObNfZbOQgFudXkFDmXb/64V -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGxMBwGCiqGSIb3DQEMAQYwDgQIjZUSrsEemGsCAggABIGQQ+r2iokCHNV0ry88 w094AZOro+EJmNzCbXHbMfLj/nlZGNaPS1xMGG6kUb4e8JjkqTGbjHCM0ryd3czS 6KCZeuQqGm2C6ui6rRtfzMedEFFTfmxuXOBYfi1uK8XAIqKJLr/Wzl22j3mSHotA n38ybvd7JQFZt4Vhb4moXsGwKBBT2cpwhMcHmspmtwWPeaXW -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ecdsa-p256-encrypted-pbkdf2.pem0000644000000000000000000000530607346545000022324 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIHgMEsGCSqGSIb3DQEFDTA+MCkGCSqGSIb3DQEFDDAcBAibocShMlF2eAICCAAw DAYIKoZIhvcNAgkFADARBgUrDgMCBwQIzyEw4JtA0eQEgZBeh88mnANFl1ZU2FVt roZqlNFhEBPo9SAs/HczbLsE4RXypn9nvVTdsKUNZvRvVIEi095YLb3F0hlqK2wD tzuj5oWjZpEKsnTZ2w+HUbyMbh1HDqSxq4pcpTHm3djjGuMzr1tBxUecrPV8qexe wobqCs+F4scVogwDqs7g10qtNUeQCYNCT8dnStvkVHaoqXg= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIHjME4GCSqGSIb3DQEFDTBBMCkGCSqGSIb3DQEFDDAcBAjDYuulig+s+gICCAAw DAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQIPCAI9QalQkcEgZB79SD4TnF6u3r2 r/uMo2OuMnqRNw+PixfZnKa/xAxFmhKymKgCnVCXnulwz8fV6tXzFVZ7Kork/s5R KUSmcRZPtT1bfRgnTaASsrKmwC01dANRsLA/irmRZNtonwtYhmpkpngM19cGpGKd COZW3HdkNpOYif2ikfLqANZ4Kr8BaxHCvBH7pZUnQ/EMDZ+diCo= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIHkME8GCSqGSIb3DQEFDTBCMCkGCSqGSIb3DQEFDDAcBAiUTRnu/r/JDAICCAAw DAYIKoZIhvcNAgkFADAVBgkqhkiG9n0HQgoECJI2zhldluaSBIGQL16UOcQDE7F8 z++qmBRFh6SzmOqGpVvHZFTaVYPWtnr3+8bmeG8VODm5AwVW11VTXnD0EH+t+bLu KBceosNMZNhlKVBdFZD1qdZO6X84UtRq/pehWBw08iMY0JiJKA7bEF1xMJXK3TV4 wA3K2ryj8r+1B9jDxI19SoTlKpB1WFUg9QFh1g1wMG9cC6JpcBPq -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIHuMFkGCSqGSIb3DQEFDTBMMCkGCSqGSIb3DQEFDDAcBAhvY1bt8cacOAICCAAw DAYIKoZIhvcNAgkFADAfBgsqgwiMmks9AQEBAgQQTKETRz1UrWanXQZlKfVdtQSB kCL/kpfUMb+r/nEplRgUQZH5y0G5pB5sT1LH3iC2NUAOEHhEBr6Pn8akByBDCrRY h+rO1SJME5oo7polnb6srxnBrkjrvKYZ6ne/3yG0LkYAKgF6nRmqNIVJVfees4ZT LjeuYMNYmgMF4HpBcpkMz7zafYeb6NXQ1UMasHN1mbIUwTPnDN8RlfssuWHLGqAs cg== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIHrMFYGCSqGSIb3DQEFDTBJMCwGCSqGSIb3DQEFDDAfBAjYLsHJCH856gICCAAC ARAwDAYIKoZIhvcNAgkFADAZBggqhkiG9w0DAjANAgE6BAgsrVp7+I4/BwSBkBbz b+11SUaYAUR28juF71s5ikLSUa7draImlFNYkAIlr5HsTvyeyzKFhGW7u8zlJZkm eYofzJ+2J4IPN26rgQ3/QEhVvlyvCyByi1HDdMuANsk7tcRrdEXotXAwQNuOteE/ /DjDWwoiVuqXVGbsgk2ail4TwMyGLCVZhCbrx/ovsLekDB1BJFWjXIPHZFVfbA== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIHsMFcGCSqGSIb3DQEFDTBKMCwGCSqGSIb3DQEFDDAfBAhfdqSzavBOTAICCAAC AQUwDAYIKoZIhvcNAgkFADAaBggqhkiG9w0DAjAOAgIAoAQIERLCMbZx2s8EgZCc ua7hkVEe7aHr1HqxKgFirPbdRB+P0ov7ymfUkfiVeUuKbLUE6Wpbf1EAIskbAFYT dMaBnqbzfbAZcKNL+1lM9xvh7yg8jWsFn4FqAezrYh8TTb+OHNBKeXGuk/qsPQ2W haxw8HAIx0Ykh0XBpAMs2hPh33FPqZsbXiRVG3zhHuD0ljCkpymx+ViIQGB1wNg= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIHrMFYGCSqGSIb3DQEFDTBJMCwGCSqGSIb3DQEFDDAfBAirhA8ZkYpz3gICCAAC AQgwDAYIKoZIhvcNAgkFADAZBggqhkiG9w0DAjANAgF4BAhfyCO8OozVEwSBkA7l lvkcjvvGwVZuhKt4B8megLXjnBTGu9Q3mhVAjIx05SfjEht7CGpNmFEZwgsITZ6l KTdFpjvw04q8J9auin4Cx9MO+wO1bXujMfHe+uVITyfFuP+s0riRmXVpLu/w8Gsz v41UEIOGPzyikE1QR7YjZBXbmKiV0I9g+ibMzI+/8gL/OzIZqdZDLQNfgIKcPQ== -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ecdsa-p256-encrypted-scrypt.pem0000644000000000000000000000221107346545000022470 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIHkME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAjA6KltctaCVQICQAAC AQgCAQEwHQYJYIZIAWUDBAECBBCxRl8OYcFksxBJJa10CqfFBIGQtgZJGAiILkm+ WAwjhv4cFYw21cC2CfWqf+5Ns1hGIe44C3wh6isgNbk2EWD41JFNs3Kh8ov9yIwj mN6qfNWI+zhCiJ8rqJp7jmec/xg+QcPX/57EFSoJr09YjhAj/rABTornyN0BU6qg d9Bbqe0fKVK/YnChjvMKjdcpKLOJKGEjs50AYFdpWj3DN5x4+osj -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIHkME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAjFtKsLQwg5hgICQAAC AQgCAQEwHQYJYIZIAWUDBAEWBBC+UkFqffq2uECRTJE0eWzoBIGQC1wqDWORz7KR 5nYrSt5sotzD+NQ3x0kR4+m7lAJuw71KXGFI2uYet7FrxKmR6UFFNcUv9/HY/TnV iNa9SWXNEPTPe+7Uyy7dHrNBdP2EZ4b1+D+EA67pH2KGPZUOgEkvNR/12Q5X4DdC XX6ZeruqOXIWu/t1A9KOXfbYwy15a+KoiseRnaRHflunbBx4Snkg -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIHkME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAgm/Gwp4kcdSgICQAAC AQgCAQEwHQYJYIZIAWUDBAEqBBCM3Ciqoy4d+2wE7C1lOceEBIGQ2RENqgg/ZXwD UtHVjHM7zwY1ZC9EDRle+pAnL/nPlGk0mnzbHt3rWZVFXVkZsTOFZMNfNYl0/pDy xwKJPp2gzOuxegNsk9v4CV/s8vxAfZEEa9wv8nfcp4F/eaaSU4cC4ofXgDp6+WAz uaMPf2yzdEdgaolfJudbYlqJ9Ufra58HctZwJR48JLTYSYBuBpHz -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ecdsa-p256-public.pem0000644000000000000000000000026207346545000020433 0ustar0000000000000000-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdiq+DUTenjFcFQr7vbN9rcwuYkiR 9kOxipGxnBFcntPNHGxt5WAENXLdmPpjhlIH90ruPGzngpMQKgNxcu8QBA== -----END PUBLIC KEY----- cryptostore-0.3.1.0/tests/files/ecdsa-p256-self-signed-cert.pem0000644000000000000000000000112307346545000022305 0ustar0000000000000000-----BEGIN CERTIFICATE----- MIIBiTCCAS+gAwIBAgIJAJf6ZvHS4D4AMAoGCCqGSM49BAMCMCExHzAdBgkqhkiG 9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wHhcNMTgwNzAxMDkzNTE0WhcNMTgwNzMx MDkzNTE0WjAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMFkwEwYH KoZIzj0CAQYIKoZIzj0DAQcDQgAEdiq+DUTenjFcFQr7vbN9rcwuYkiR9kOxipGx nBFcntPNHGxt5WAENXLdmPpjhlIH90ruPGzngpMQKgNxcu8QBKNQME4wHQYDVR0O BBYEFFPacwYxY7UVPo4lqM6c72CnWEdXMB8GA1UdIwQYMBaAFFPacwYxY7UVPo4l qM6c72CnWEdXMAwGA1UdEwQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgC8D3epwl GR7JF9+v0grNhBeRkTfSqcIHOUR+Z9QKVqACIQDQZArMqLAZO/q5XWnCOmurIjuH R05sQRKTcoxBFr7nNw== -----END CERTIFICATE----- cryptostore-0.3.1.0/tests/files/ecdsa-p256-unencrypted-pkcs8.pem0000644000000000000000000000036107346545000022543 0ustar0000000000000000-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg3UFxuuhLhGtIv3w5 5GbQfOjQ84jaT9KQbEqfYQ5u/f+hRANCAAR2Kr4NRN6eMVwVCvu9s32tzC5iSJH2 Q7GKkbGcEVye080cbG3lYAQ1ct2Y+mOGUgf3Su48bOeCkxAqA3Fy7xAE -----END PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ecdsa-p256-unencrypted-trad.pem0000644000000000000000000000034307346545000022445 0ustar0000000000000000-----BEGIN EC PRIVATE KEY----- MHcCAQEEIN1BcbroS4RrSL98OeRm0Hzo0POI2k/SkGxKn2EObv3/oAoGCCqGSM49 AwEHoUQDQgAEdiq+DUTenjFcFQr7vbN9rcwuYkiR9kOxipGxnBFcntPNHGxt5WAE NXLdmPpjhlIH90ruPGzngpMQKgNxcu8QBA== -----END EC PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ed25519-encrypted-pbes1.pem0000644000000000000000000000302007346545000021402 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MFcwGwYJKoZIhvcNAQUDMA4ECLtv2JchVem9AgIIAAQ4cVbXStmw+OANljhnJppr YqzWhH0zLXu+SohCnQ5cb+R0AsffwhT118Fedfi6w2b9RAL8EhvLk3Q= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MFcwGwYJKoZIhvcNAQUKMA4ECAHGvbJ4ns9TAgIIAAQ4GXgJkD9MzX1OzBP/Joo3 5ORepS0PLaDUk6yYU7jfD9ov3JZXnxxAyQsgfwIJcJHE0lDm8IL5qUA= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MFAwHAYKKoZIhvcNAQwBATAOBAhN+aPvlVgjrgICCAAEMEd+AOxYLmDMzouXzEo/ Z4XCVMZrBGGrQIYSL3d7r/sqMHklH+SC0JtdrVHzJyCuhQ== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MFAwHAYKKoZIhvcNAQwBAjAOBAjCex3tcisjiAICCAAEMAgOe/PJs/m84I+QR2TY ojYndqNX4lWnQs6rl5YK94QB0V5rDZWN9YvmZGmX+/JwkA== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MFgwHAYKKoZIhvcNAQwBAzAOBAgmU1ToGVo9cQICCAAEODaxyq/B/HNpbpsDCL/w fYohLS5QA3s5OIKHo9uELz2GrTS7aI7idAEPY+iFo+eFD6Ql5gy7GVkb -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MFgwHAYKKoZIhvcNAQwBBDAOBAgiVSOpDt2NGQICCAAEOLpMO1GOWTMQQ6MN0F+u LyTzAruvs3lbad5wd0EyGE10m8c+2vXSsl6DMEkaXrjRovsCebZwVzK8 -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MFgwHAYKKoZIhvcNAQwBBTAOBAjdfsUUZ9k3AwICCAAEOERTz7/lepT7BrKWJ1L+ IilhhSxYjjeHzCNYGoz8+WIRhcykLlZHnAcVTNXWkhNjMf8MEUmfh9My -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MFgwHAYKKoZIhvcNAQwBBjAOBAhwossvpdyt4AICCAAEOBQ2Yh3yt8lrCppVUJGv W7cdL+6gH1H6dL+cGeOsVnpFUNwnEQS92OLQYENAO4B9vqYgOhnq3rDF -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ed25519-encrypted-pbkdf2.pem0000644000000000000000000000360307346545000021547 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIGHMEsGCSqGSIb3DQEFDTA+MCkGCSqGSIb3DQEFDDAcBAhYNXHDae7APAICCAAw DAYIKoZIhvcNAgkFADARBgUrDgMCBwQII/ySuK0RdrIEOA/iQWXFUgSRi59Z/okt ab+6coDwGEB6ywo+ysTpEwSTMICq6xWcp+BnACzs1FWrlYS/wWDxzeKy -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGKME4GCSqGSIb3DQEFDTBBMCkGCSqGSIb3DQEFDDAcBAiKSUa4hjdNcwICCAAw DAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQICGrlfM+5tqAEOAtOZfvoEAPcFs3P k/D46jpfdBroO7vU3Ki/6+2gRWrnjWWL4UyYoMkT8ZHVk4uOa/4mvnakkU16 -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGLME8GCSqGSIb3DQEFDTBCMCkGCSqGSIb3DQEFDDAcBAhMNKAxJTPu/AICCAAw DAYIKoZIhvcNAgkFADAVBgkqhkiG9n0HQgoECHiEUPBMhqlQBDjXy5F/zsQz/cVA F2QfS7D6zLuLjwPsNGX0m3+070d3usNVdyogbViSEhcbvTmOtjp0DB0BNMPr0A== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGdMFkGCSqGSIb3DQEFDTBMMCkGCSqGSIb3DQEFDDAcBAgrm/IrFyklqwICCAAw DAYIKoZIhvcNAgkFADAfBgsqgwiMmks9AQEBAgQQCsvDlOh1VOEXubKKcLMWugRA GRNH/la87zQtE7qPP8SsTQgY2/f10rEHLMZ80ysfVq0oGmRfrN79QZETYLdsckWt HmJyslMCCCswvM8o6rt1wg== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGSMFYGCSqGSIb3DQEFDTBJMCwGCSqGSIb3DQEFDDAfBAhuP6SU4nsQrgICCAAC ARAwDAYIKoZIhvcNAgkFADAZBggqhkiG9w0DAjANAgE6BAhgU/sm47TbAgQ4wCSj KK1+rp72Ucw107jbsrffscMFx8NoYYK2RzxnwDZzjiy23bBQlxlEZ94Y2BzNT1Hi WHJBcls= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGTMFcGCSqGSIb3DQEFDTBKMCwGCSqGSIb3DQEFDDAfBAiXc8D7B3BAMQICCAAC AQUwDAYIKoZIhvcNAgkFADAaBggqhkiG9w0DAjAOAgIAoAQIQBrLaUdGxWoEOJvN 6DN4SgKuaFDap+JvqTmx2yKEEr0+0HbUMIVUOZXaiw1kVmLCR/jaoLUJGz6rjSGv 9RPCtrvw -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGSMFYGCSqGSIb3DQEFDTBJMCwGCSqGSIb3DQEFDDAfBAjxi1l3WQPQPAICCAAC AQgwDAYIKoZIhvcNAgkFADAZBggqhkiG9w0DAjANAgF4BAgj4x/sdHkh0QQ4eEY9 UwHGaNE9AsBfjCUTjVRzvrJedZvbPTNIAjipMYW3uYzVcg5I+GE/4V7yhKUzBipS RLxOGtk= -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ed25519-encrypted-scrypt.pem0000644000000000000000000000150207346545000021717 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIGTME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAgale+OTVw8jgICQAAC AQgCAQEwHQYJYIZIAWUDBAECBBDYon9Yg2PXUt8HMaRZW75QBECKmy2N93fMD8+d dpTnG3bXuLETOhn/SGCG35Pgzvp3gZoRR/tksLS0IBXdmbvjRGmMiWcMZ57Zcd1a PJvyO9p6 -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGTME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAjA3W23hPPCvwICQAAC AQgCAQEwHQYJYIZIAWUDBAEWBBDIidXH5KqQ5BsAcSf+VpjxBEBuN9xS3T/q39Sc gVXmgBTsfD9XI1owhsiG8r49GF6iXztnyJPMIYDMkjsnk4ypdffSTXlRpRUv8lIj vGE7LUbr -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGTME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAgrfV0wImuOLAICQAAC AQgCAQEwHQYJYIZIAWUDBAEqBBDglOp/wHw9J8ue05R8hroDBEBP2X9ptHWTKrb+ WwyGW+s2MuVulF4In3RjYNld1ZYQeeQk4Vnqwq9t+2djgXsKL4hhwEfhk0wCH64b z0EbHIzA -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ed25519-pkcs12.pem0000644000000000000000000003701107346545000017507 0ustar0000000000000000-----BEGIN PKCS12----- MIIDSgIBAzCCA0MGCSqGSIb3DQEHAaCCAzQEggMwMIIDLDCCAj8GCSqGSIb3DQEH BqCCAjAwggIsAgEAMIICJQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIGFEN 2HUjTJMCAggAgIIB+MiKzSuuknXax1GE1S9jQ2WfuaNablKCYNUB6wAQJkqiwUjC DhW1hAcz+4o8Ow1NmuGNiTR/9RKp9ZJmU/GFQCfKInNRL/4WzgQ1l5pKIYYKmKgH YA5Ci1bnVA8SEXvQxto7K2maWrxvuSxLktHo7ajYfI+Ze5qiGYET9TqWXRiql9ld oxbtTFDkSzNC4VxqU8HYkZFx/4ld6oKJZ71QaSZgf4t9+BkHNfOknOhAp39WKOhy 3UBmopdBUPpqJAdAPQmR5BUeRibIC+3RllvRW/FLOW/FwfyVoQESUu1u2nl4C/8z t3i14EVcKuNbBvz0Qja+4fO+p6e9+q6clFVYCU6UvZQncKX8mRdCSGDZOla018L4 Lf4SauXnnyyGk8bEI6kqATtkPh/pK3nVBcjboX437+ZbGRj4H3viC7rBijaTizlx gb8FhVaryk5bwlzBJQUrtcndd5WdjCYhZPMaB/xFxqSotWWzvxya3A0Z/SgBKj3I 6Dbv+hGIGACVfcT7k9W7pPC8QaESOCZJOqzckik4h9huEyyDQyvxKa18l+RXA9AQ uop3gtG4WRiosSxzgNPh2e5RGVM40AY3ktrsuilZP9skDMF5viTin1C4p7rPxD3s dzs5augp0VppJTA74czDilJs3f/u18PPQS2r92ckcM836SDbAjCB5gYJKoZIhvcN AQcBoIHYBIHVMIHSMIHPBgsqhkiG9w0BDAoBAqBaMFgwHAYKKoZIhvcNAQwBAzAO BAgHTXORITxbIwICCAAEOHln0Ez/AkpJiI7hvzh/t01Rsl0foaq6Mt28OJNcaLLH CoyMtg2TTSDWlxrwcTc8A2Ug5mf5jzFPMWQwIwYJKoZIhvcNAQkVMRYEFBUJzG3C AW0LFRvdr7FoWoQ3wIq6MD0GCSqGSIb3DQEJFDEwHi4AUABLAEMAUwAxADIAIAAo AGUAZAAyADUANQAxADkAKQAgAC0AbgBvAG0AYQBj -----END PKCS12----- -----BEGIN PKCS12----- MIIDkQIBAzCCA1cGCSqGSIb3DQEHAaCCA0gEggNEMIIDQDCCAkcGCSqGSIb3DQEH BqCCAjgwggI0AgEAMIICLQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIyxVd QGw+wjsCAggAgIICABwReIhjPnmxn4HZySDDd8+z43vHNIlplmHIKyKuWkdPZNHi knA/nqebK2gdLx5hcauatxUVEQCaob/wzbxPfK86NDbf/2LsZqm8TiZbMz69sqxY 2M9QpjRY5WKPnbA8s0uhnsdm5UxCHF4E2omZA6yqPcGIioleCJ+d3b7U74v0uxn9 SjdAY6fw2mJo155sTZHaK0GucDmzz0h4N8RzDhURTwxMy9eXEaBy07rRfDJ1iFTB YTWNOu++XcwvzWxV8h6EEEBbSE0kuLbnPwN4L8kcxZV/DhlW6QbiwVOJWL4dyQ84 FzxkdIC5lzhvw0lzOGM1WMI27fvFhHXzmRDTPJRZhsjLAZjeJwlw6CDY+04VNi5k PzoC/mQgRjf8BDCWMyHcHyimrlm43OuIr4lW3qfLP2bUHue6f8ppZq6napC1V86P bTsYjoDrS/gFwjpieA8JjTVV9yWu+IRsA22th/ensplyfwU/wadDOXJFLvJrP1tL EavSjphDR1+VSXI3Xp8k/g+RJzxd2P0sTcUyqCTGDCJKplYCD8V/azfitlGfretp SFHqVVV/1yaFAZu+fI1IFN3YiSqeJrjbGeus9hhLs5jsiFzol3udh9whmp09rYCS 6BPXi0m+izvcLgffoLwjidx2hvwSbRjTUTj9iJGlz/Bn16djzDgyTlJVOm1fMIHy BgkqhkiG9w0BBwGggeQEgeEwgd4wgdsGCyqGSIb3DQEMCgECoFowWDAcBgoqhkiG 9w0BDAEDMA4ECLuL8XSr9Wt3AgIIAAQ4sIhPGPPiVe7pC3a9af5gSKLNIdbbdYXg DvnsCB76bZQDkWXfe3+eKwU0RjX4Tf7sEKBSitUQdyMxcDAjBgkqhkiG9w0BCRUx FgQUFQnMbcIBbQsVG92vsWhahDfAirowSQYJKoZIhvcNAQkUMTweOgBQAEsAQwBT ADEAMgAgACgAZQBkADIANQA1ADEAOQApACAALQBtAGEAYwBhAGwAZwAgAHMAaABh ADEwMTAhMAkGBSsOAwIaBQAEFHPqC5cmwg+m5BlOEYjZTtH8iD8wBAj8srMZ8dqO YAICCAA= -----END PKCS12----- -----BEGIN PKCS12----- MIIDrQIBAzCCA2MGCSqGSIb3DQEHAaCCA1QEggNQMIIDTDCCAk8GCSqGSIb3DQEH BqCCAkAwggI8AgEAMIICNQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQI+m6G P6kpcWcCAggAgIICCL51B8K3PIhgUNA8wpwp4dad0LOS8IbVvrN522K3/urilvQl ZuxvHgWhbg8vm47LYCZD+M8k3RHXSR5Rdd9qCOD44bVwFlM8Fq0yYg9hMjhGPgMk SYKGErU2OppX3FJPAL397BlWTMpvpvH9t0nEnvAcEOEFHWytTN8/80Pl2j2lseGS OEMCahKZ5yfLcNDl+SGA2hfi34he62i80LWWJye5UzPEKJgRU2KAIR1OMciGnpmN E90ozaZbgrZqnwI3bYYpAGMPBWwgpp4CVvBpJxT5wkw82TaC9WXNutXQmBWri1cC HXrkeqG7lO2E79AkJANVq0LSaVhcDb5lYoqif7oom9W7gA3SoFQdN8j6LE9XyHTc wGCP4jspnA66fGECOIerziF7b4EfQEIFtmX6DSpE9WCjL9MoU8Ftxt1UzY6WzXSi LrsSUb9R4sdkzjzkgw67r3UAyvO845qnXxNaUtCPPOq7pCSOwPNaecqSwNxQgxZg xo0yyZbm3bjyrLK1suvhegk9TANTNjmyaYhQ/DyO07+V3ee01rMYVOre0hWliQRW bfYh9cGLFKfQcMmwRv1bCUV0D8keOL3iTxQM7ReyIZeJDIqHfDckhWgbvpBs4dBX GFEimDEsLfXjFPK8M+z3V9Syi5ywigwICyvXIat1NspD0xcTkp4BhKCVNct0m2Mo 7r2LA3IwgfYGCSqGSIb3DQEHAaCB6ASB5TCB4jCB3wYLKoZIhvcNAQwKAQKgWjBY MBwGCiqGSIb3DQEMAQMwDgQI5KEgbc5PTYACAggABDhD49uTQNK70taieGdPG4+F jDIhYIWX4BqI4Op+i5RrLmZLLh8IIwS9u54L2mU8iLixcUGJM7hwdjF0MCMGCSqG SIb3DQEJFTEWBBQVCcxtwgFtCxUb3a+xaFqEN8CKujBNBgkqhkiG9w0BCRQxQB4+ AFAASwBDAFMAMQAyACAAKABlAGQAMgA1ADUAMQA5ACkAIAAtAG0AYQBjAGEAbABn ACAAcwBoAGEAMgA1ADYwQTAxMA0GCWCGSAFlAwQCAQUABCA9iAPHbYTZUVBGKEN8 m6ecISHakuyKxNOMdo9sjrPOWQQI1CwiN3JXU8MCAggA -----END PKCS12----- -----BEGIN PKCS12----- MIIDvQIBAzCCA2MGCSqGSIb3DQEHAaCCA1QEggNQMIIDTDCCAk8GCSqGSIb3DQEH BqCCAkAwggI8AgEAMIICNQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIhOBk A4W2LFMCAggAgIICCLYRPF4zD4p8DxHKzg+OJXB2KIb7k/3LvCOt5XdpFuicw9Z9 oBVviniBOI9AnzYwIm8lKCtfEazSY7jfRqX3tbLNltN6uBr8EaQM6mu5glgHccEF LG4A7CNgks85IwFovCj4zT1zE5PrT7B8xUmLlMCGup+dImlmBPvzUaNcqq4O3mg+ m4NkCI0qW12LTczdy54mPiaNXaklqQHjHBSEGugtMexm9CWV8t2bXuZsZv161NKj d9lu2EfVN+GutIervK5MOa0o91+VjdFWh4UW7GjWmlFfvCO92dg2BXnm+J+sSV45 PM3UyM9DhxjJjYpv8E4Qm0AH3ylx/WY+23AKa5LzCokfdrPOfYC4tQWDZhtxclvl bZ2KDJ9TUaNoXB0pdaSYppgn+AfMTPacgtDRTVfWE7TbnyTT9GV67kNhZeeJnyuP LwjjGT/F1HqjiQswz3+ssdIjsfXv2M3laCF30kWrsRj+nUx9aFbplovYhm+Bsimo GBsk+JSV8aWDO5v9WInQ0nX1qdMj70edt3U/jU+8fXrdoGshyJlJL5vhTN0lrUKR y+Rugp6DGu2Jh4C+8Plzt3rsck+VR1anY3sLqYs4Nm8NTmrlO5W6iVJI96i6Wkbi kCkQ+8FZAw+a5NvNX9fY1BfFLGCGAcYBJsKXATMP4e5Wu2rpefYMv+gtLBVgVoDh A5vGr0UwgfYGCSqGSIb3DQEHAaCB6ASB5TCB4jCB3wYLKoZIhvcNAQwKAQKgWjBY MBwGCiqGSIb3DQEMAQMwDgQIEbbZB/ZOFvICAggABDgz1+uoucIRZUyWxQCnM2Z1 VrIDzkjSRnzfh63gtKAYax2kaYUzpGnZMY4DrYi1WQDTmnfTY7XE7zF0MCMGCSqG SIb3DQEJFTEWBBQVCcxtwgFtCxUb3a+xaFqEN8CKujBNBgkqhkiG9w0BCRQxQB4+ AFAASwBDAFMAMQAyACAAKABlAGQAMgA1ADUAMQA5ACkAIAAtAG0AYQBjAGEAbABn ACAAcwBoAGEAMwA4ADQwUTBBMA0GCWCGSAFlAwQCAgUABDAzqjArAvU6yK/h2AkT +5m4+jU4enOBGOCCtPDy0+0jaM1EkyDTqYyxoxsQBDXwSS0ECLaGyXHiSBnYAgII AA== -----END PKCS12----- -----BEGIN PKCS12----- MIIDXwIBAzCCAyUGCSqGSIb3DQEHAaCCAxYEggMSMIIDDjCCAhMGCSqGSIb3DQEH AaCCAgQEggIAMIIB/DCCAfgGCyqGSIb3DQEMCgEDoIIBczCCAW8GCiqGSIb3DQEJ FgGgggFfBIIBWzCCAVcwggEJoAMCAQICFEInN18eR8QZFfy9Yb39ycd56f8PMAUG AytlcDAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMB4XDTE4MDkw MjE1NTA1M1oXDTE4MTAwMjE1NTA1M1owITEfMB0GCSqGSIb3DQEJARYQdGVzdEBl eGFtcGxlLmNvbTAqMAUGAytlcAMhAPb4Tt742Tc9pS4/MMDFCjYzApuBncDQ5JWS 0QL4ejEUo1MwUTAdBgNVHQ4EFgQUV4Bp7nHkyDQxsCEBe5xqQauBKXgwHwYDVR0j BBgwFoAUV4Bp7nHkyDQxsCEBe5xqQauBKXgwDwYDVR0TAQH/BAUwAwEB/zAFBgMr ZXADQQB+hVuzD7hONYSSQAZ60fo3ZBjs0R/guNoOWIGBCgSxaqhs//Np31/mmiZF bsT67I2lYUyh0ogms4Y2av5dJ40FMXIwIwYJKoZIhvcNAQkVMRYEFBUJzG3CAW0L FRvdr7FoWoQ3wIq6MEsGCSqGSIb3DQEJFDE+HjwAUABLAEMAUwAxADIAIAAoAGUA ZAAyADUANQAxADkAKQAgAC0AYwBlAHIAdABwAGIAZQAgAE4ATwBOAEUwgfQGCSqG SIb3DQEHAaCB5gSB4zCB4DCB3QYLKoZIhvcNAQwKAQKgWjBYMBwGCiqGSIb3DQEM AQMwDgQIX1+nSa1n/HwCAggABDjgLTq2CBAruDxaYp+1TvD9bU2VV5rzE8J4e20O 1lH1ERi0gHw7nLtjAsxBWVI20NOyalAB0cG4LTFyMCMGCSqGSIb3DQEJFTEWBBQV CcxtwgFtCxUb3a+xaFqEN8CKujBLBgkqhkiG9w0BCRQxPh48AFAASwBDAFMAMQAy ACAAKABlAGQAMgA1ADUAMQA5ACkAIAAtAGMAZQByAHQAcABiAGUAIABOAE8ATgBF MDEwITAJBgUrDgMCGgUABBRTDkUp0GY2M6X+Hz5M0GBAj6ZDYAQI8L4NQjeGa+4C AggA -----END PKCS12----- -----BEGIN PKCS12----- MIID7gIBAzCCA7QGCSqGSIb3DQEHAaCCA6UEggOhMIIDnTCCApIGCSqGSIb3DQEH BqCCAoMwggJ/AgEAMIICeAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG SIb3DQEFDDAcBAjB8PuFLlFLeAICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQME AQIEEBPci+1MGZrIWpKRWObpG4mAggIQ0CxiJz+08OHzg/h0QX5++RjcH3HeyNs+ C84tjzJOcnRe1xRZ9ritRaPuFN+FrEXn73dKJmTogpXvGGlfxomoHyVuLRl1HBbf PUz+rhj4NHoRfTVBwqaP3GNO7zOmipqQrMi7wZTtUtxaXgRzsEruHCIe99T+5MUQ OCLRqhoHh7ukwZlAyYz/dtdnk3Q0GfQAmQjhf1VEsIMdE1YwcQBInA3B08uPFSnR JG0J7Hs164wU/o7oust8uPxuGnmEJjcQ3DwCIHN+5cLiRmO5qnZc6lGKhJnHGEWI BoziLgj993gkB/2Ir1RwWsze05bp6XPI6irRUyLOkC4WuSOFzTu2ck3fL+tVgmtK wUSO93WwWspDNdQX5kR/gIl9WbAYWkCjAhk145dlXRTlJxpksp5taQF4dY3GHXs4 NrjCe5773t/xW1k1kioZL5mIjT2p9MUM2DT5wkbpd9KI76pIB2BEjiAo+cZTJ9e+ Ck9JnUrck2gSYg4CloGabMXt9nsJ+V4UpcJm2eXAlswno4cxFmXKlT+GtqzzKQH1 sp7YAxrdqxATlwsyD52rEJo/rKOoFt6dyDcc8PLdXrErfoY1WAl+Z6p4iDp2VYqr GMx0R5uArjhR+R7rmGqTfwDFgc6pp4HWBwGoQ2ZfWcpQBUNJPaZ4o4uEpd270XNR mW+BQMXXbsRTUK9AT0iL7vCFVdyPQg4DMIIBAwYJKoZIhvcNAQcBoIH1BIHyMIHv MIHsBgsqhkiG9w0BDAoBAqBaMFgwHAYKKoZIhvcNAQwBAzAOBAgfExpEdcn3jAIC CAAEOOoKa1gzF3tuBnPxpeEqkeIrPQl+t4jyzFj11QC2QswhPTcc0NLIisoTllk0 m8VrMAhZzbz7xHcTMYGAMCMGCSqGSIb3DQEJFTEWBBQVCcxtwgFtCxUb3a+xaFqE N8CKujBZBgkqhkiG9w0BCRQxTB5KAFAASwBDAFMAMQAyACAAKABlAGQAMgA1ADUA MQA5ACkAIAAtAGMAZQByAHQAcABiAGUAIABhAGUAcwAtADEAMgA4AC0AYwBiAGMw MTAhMAkGBSsOAwIaBQAEFF0dkSA5il/b6lVIdVS9t3Yh092sBAi2pnHLHUDLgAIC CAA= -----END PKCS12----- -----BEGIN PKCS12----- MIIDzQIBAzCCA5MGCSqGSIb3DQEHAaCCA4QEggOAMIIDfDCCAmcGCSqGSIb3DQEH BqCCAlgwggJUAgEAMIICTQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQUwDgQIksEU f1NeOYYCAggAgIICIJSOWj0qBbk5tlV/M5hekb8fYtjFVjbN287fAaWFEHty1EXo 6B1wKULhaIBJdlFDa8feE6icJOtYHwtiGKRAfo2HfAeu4IsHEY9Ejvbq/vT7QTH2 GvKWmE45mZTavedRnSLGBq9/JAOZMvVnIoW5DKji1e+piXP8sTAn7R6QWIELvf7l LU/u1dWOZGWxWkztLAAU4E/PhAYlVMkOD0imZIYcF1wKhqpZUgzsq53AdOWBghz5 7Y54rULci1kZ9H0e/YvUGsB2ahmJtgO6vCLwi06+ohQ5ONzHPYOaZ+yKiBou+w4I YeOLlk7zTDOFKAVgEHsg2XSMvFRVnoPDm/UxYzITKlmyu9WWptmQnVtlf0YKK6aE lirn10ZUR4oO5AxlvNdJyuBOHFb5z0eEGXta+dKse381Y6lRAA2/nA7z5+3fosch MeU0Jc7D/ZWWCmPOsLzPvWWOGYTxU7iba10iMhEvT55qCCMrYQAEJ45IwWItKCMY aKiNZythBWiajke41tZYWgsVcl0PcDTlrmqaOcGCKJt797hH9QrfGlnpRZ65dIVY LR8QSjZJl30doV6ga56Y2oktPvQCgs6MLcCU/QlAGTGmneMRnBwm0EgU/fQwg7yj tIGwbkd4z8Fw4quRnAcvjrlmePM1vRo5cX49KGnq26WS+oMLWh6cGotVPRHZLzbA gpLUBEv5HUYLS7vEbTp+TCn57OFrXgXXuxR1UmUwggENBgkqhkiG9w0BBwGggf8E gfwwgfkwgfYGCyqGSIb3DQEMCgECoFowWDAcBgoqhkiG9w0BDAEDMA4ECFwonOIg +flzAgIIAAQ4kpdDC/If2Ro8CTME3LIf3OvZw38/CliPX6Yy4MLI7JSME5RQUrhY /Saw4/L6B68mukeWZMBnOmExgYowIwYJKoZIhvcNAQkVMRYEFBUJzG3CAW0LFRvd r7FoWoQ3wIq6MGMGCSqGSIb3DQEJFDFWHlQAUABLAEMAUwAxADIAIAAoAGUAZAAy ADUANQAxADkAKQAgAC0AYwBlAHIAdABwAGIAZQAgAFAAQgBFAC0AUwBIAEEAMQAt AFIAQwAyAC0AMQAyADgwMTAhMAkGBSsOAwIaBQAEFGs4YBeZuWInWICuG68IQgRV jLS2BAh8zZrG9uqvuQICCAA= -----END PKCS12----- -----BEGIN PKCS12----- MIIDwwIBAzCCA4kGCSqGSIb3DQEHAaCCA3oEggN2MIIDcjCCAl8GCSqGSIb3DQEH BqCCAlAwggJMAgEAMIICRQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIk4KE evBBgTMCAggAgIICGNsQ9DokOToB4WN9X0SQpj0yKDTMzWWiJWouEdbnH9rpsLHB oxPJRSdvl6qYD9BDIIyQBb72/oJEyv9x4vevZ4Y+dr7TI5iam8cqf/jqCRDcJngJ F1OeoGw/48yniY+wLLX9stA7mLVlGOqmkv5ubr4oS3B2DvMgouaiqOzBY970zepk aI8v5bDciknvNxLcqwb8gef9qSi2lXjSS+da1r/Auv8wy1DWMb0wXppkr6iE4eRD GBrJBCV0+0GkdlEQdZlUwF9L6Rk5Gh6T5sfqb6MfetbKdJ9o6ZZsgBiePVco0yrV gPVCaDkZwoIH+iSixn0YOqVjzWrnARyWKdf3esXGloIQhQnrfuDIdHK8YBlXuN3z EfSmfRh/+aWG2DW4s9wcAB1t3GMZewMZ+z+Wrie/sYgp2o/105Q8dUQqNDu4JBYH 1xjfqyjlWOtzEyJk1wrUefOWIFlHkzwZcGrY7kUSJNWY+ljm+ZZbvJWQE7mPXet/ yZFSXv42FwFwU0C/Lo8BFI2c0KC4CVuFNmfNWToJfa9nnEvInh2rra/XyuyeHHRe +Bc9CMCkKWnOMoC/p3jnjatqjsJdHhXVViJQcvxjJXwyJpRi3G2v1SWz6oWFx0eX 7K+rZWnrTT3QI9vSX6aCQXcgc9XNRtdObvQ1tToOt+qgvUBerqDjmvTp6eKsNw5a Z5ZxH7oqjcWgnQIYfT2aEKMQ38RMMIIBCwYJKoZIhvcNAQcBoIH9BIH6MIH3MIH0 BgsqhkiG9w0BDAoBAqBaMFgwHAYKKoZIhvcNAQwBAzAOBAi7tsvABCrGugICCAAE OL5EeTq4HVyV26RNPe2S3AKQyGxNzkwMJMBGyhIG1XPPLqumvDgJqrPcAD/QwRVj MiJb51N45xC0MYGIMCMGCSqGSIb3DQEJFTEWBBQVCcxtwgFtCxUb3a+xaFqEN8CK ujBhBgkqhkiG9w0BCRQxVB5SAFAASwBDAFMAMQAyACAAKABlAGQAMgA1ADUAMQA5 ACkAIAAtAGMAZQByAHQAcABiAGUAIABQAEIARQAtAFMASABBADEALQBSAEMAMgAt ADQAMDAxMCEwCQYFKw4DAhoFAAQUzx421ERBMyF/yNxR0GS1DLlMANMECPiknVVT vYXVAgIIAA== -----END PKCS12----- -----BEGIN PKCS12----- MIIDZwIBAzCCAy0GCSqGSIb3DQEHAaCCAx4EggMaMIIDFjCCAkcGCSqGSIb3DQEH BqCCAjgwggI0AgEAMIICLQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQI70+G ehLEN/oCAggAgIICAHqLWEksJuuLz0gv91JjhDKOXcFZFi0FPLkid4IvSGamAOBt ABgWh2v4GydPxAnLdeggMYwL/mjudrWuymgUu4fjIvTLZi54duYzBr4B+iMShlo5 C/kc5qTqhWBqPfRi6b9q1ryWZQuJR5j101BLRU90axIUpT7g8UEWzmLtEZfbZj7m 5cXWI21H/3WmzrbhBT+MBL7PeSmAL7SB3z+jGpqjIAlgDSABWpINyKQIGTpwAQK9 v1y8nJ+VfE+V/MMz4nVBdzpiP8eczg7v4CeJq/AhLU1zYS/1wRs0Smgh4azn+Hpt AoY7KfiashHgZnQOQ/YCKoUwDBoZg9A3tFiFHR6FNXXX0VChUzPEbfAKtzQ+J9vz prl3uIBvOmNbPLK9QUOgCRfmMqpSzqx7WCBU1KHynS69KBtEQCrxphItLzLon5K3 uFjuavUkGab6WexWZC7yuVihFZbRunXjrqfP0AMG98f6iUhSLKmyzHqho1Xx/vdJ ly9BFt0lo4ZV4dySYLy8fOSOw2GqvxFEVj+Giz0a4RCC2vbK5IjyTf95lsp3qiFC fBwMhv39AtapGQVdVqMrA5P5TFplSZoz2dpnIlPwCbpyvpEe8LKc6oUpu5eKmCeU RQ0zj4+J8KAzfVbzS1yMJe+umu95i5vfEUCs98C8RvDCnHsx87T/x7w2z8b2MIHI BgkqhkiG9w0BBwGggboEgbcwgbQwgbEGCyqGSIb3DQEMCgEBoDAwLgIBADAFBgMr ZXAEIgQg6so49BSrEJR5mdkomLkSagSPGcNJIanjlT+3V6/L/e8xcDAjBgkqhkiG 9w0BCRUxFgQUFQnMbcIBbQsVG92vsWhahDfAirowSQYJKoZIhvcNAQkUMTweOgBQ AEsAQwBTADEAMgAgACgAZQBkADIANQA1ADEAOQApACAALQBrAGUAeQBwAGIAZQAg AE4ATwBOAEUwMTAhMAkGBSsOAwIaBQAEFG+LXFJAkw20X9gqruZyFGH+jWmOBAgD bdl51a1P3gICCAA= -----END PKCS12----- -----BEGIN PKCS12----- MIID+QIBAzCCA78GCSqGSIb3DQEHAaCCA7AEggOsMIIDqDCCAlcGCSqGSIb3DQEH BqCCAkgwggJEAgEAMIICPQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIow4v Lsy+8FoCAggAgIICEA1VfaX02WNEBrOhNyi065Y2/GOi/rq48aMVrxk66tdu8J1A scvnzo7ZKJAb0f93U+NUwP4BTvd93vYmAPa++3Mq+alBZvkT+OM+fmIbI8ZACvlr 6B0FjU4+GOLferGud5k7GopaRjVnNErXPBtfmCi3xqfrloRZNaJo1PQIrVXUpGfK xB5iBQVIyTFZa9CGc0OFenGbegoWhR0NEa7M/M4zynaY+4HNEqv+yY8mm+aiim2E r/Q3e5zHdr63k90ltnA+xpNyjeaLhBHixgD1njzPvHkhNXenss+GIMi54pmSz52N gRX3K9ZwT4eSOQwh19fAJmK2TpCgGyffuoQMRWJfhrAsZdLoLzpOdaL9CR0FEFwy mB1j41xMcKe2yoSOGi8A92Lbkk3xN0c57fECcLbwoaZZyegAqAYA94xr4M6yzvpq 7qVZKNaB4F2n4iGbfwRgendan7LjTfPhyesjuph71/ee4WVygOm1HEq1lqLS4LzX FFwINo39oQTAIYxoXK7u8V5f/3Qj6DgiQkVMdvwn9qi8Sf6BG6AvJw4cjSbb8g7Z RQ9lUaRtVx0vSjxd11fOp2etNTcvxDfM9du4lT2lKxJUP4ZHiwWveCGukXwaVs7J BGzhCB9X9Lju9OdSjzWRPe/esHZ3uyyKif+uKR2st9pMq5QHwK53lkiWfCdnLKYA U+bgNu+U+gZs3xPpNzCCAUkGCSqGSIb3DQEHAaCCAToEggE2MIIBMjCCAS4GCyqG SIb3DQEMCgECoIGeMIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAj3 PgR467622wICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEAQIEELWZsHeLIm5n za4zYKSmtdYEQNaOREFJzeUI9EuL/4xTKOTRWK4kmQ6rYPc8/xbtUTdARKblfWGd POrYXUivZPNJEn38GCAWmNsIWGGOVc5kO8UxfjAjBgkqhkiG9w0BCRUxFgQUFQnM bcIBbQsVG92vsWhahDfAirowVwYJKoZIhvcNAQkUMUoeSABQAEsAQwBTADEAMgAg ACgAZQBkADIANQA1ADEAOQApACAALQBrAGUAeQBwAGIAZQAgAGEAZQBzAC0AMQAy ADgALQBjAGIAYzAxMCEwCQYFKw4DAhoFAAQUi8/XCc5c6tAh7OhhCR2ZKE8sCdEE CEeT/cMXItocAgIIAA== -----END PKCS12----- -----BEGIN PKCS12----- MIIDwwIBAzCCA4kGCSqGSIb3DQEHAaCCA3oEggN2MIIDcjCCAl8GCSqGSIb3DQEH BqCCAlAwggJMAgEAMIICRQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIRRt1 aGJ9pBoCAggAgIICGFNFd2VuEF5PLthNtYaAYLz2s4nHfzIM0J5BloKddcY7yeIB mj6xMGPO0U2BKmRHk2lBtWkLRI1C7La+aLv/wqccnSq+gpXVfHGx++rOx6SDqjXK 53VdIrEGWIfYkJE3HqF/WCeuvot+qBK1JiRoJN1Sb8MSXHuoIjR21ic9vJzjGLI3 hyxmzzekk0TZ/7yfdoWc3MU76ZlBGMzVhbfHlz6Oi1GG7J+TMs6hnuO2BDJMSAAV 9C8xwU1B9RAiDsZXL3lCq8My2+u5BCNoYOcuPnvMlk1quZjuMuQJvFJH0ZfRnf97 zItYGcqNqxWbs3S61ma8T8jYZi1eL0hvD96n6Im+FRF63aAgeXWXLvzgGJ2+u58W +OrKEhpu+ipPtdwdWR46A3m8+jyctNolC8X/1goLs7EDDGfjQ77KIWaHxP5G3Ez7 v4dB7IlRIjHwoFwCd5TXiORrsQQWwtnSgr16st6cw2ObLjUeFKlAGBPYE1hP3rbR 6r3+nMsH8J58cfvqmpL0+ZnFvIVZcJtb5GG7FEoeVhQM3ZdIZjmXreF7cwe6K3s9 cnF2v3ikQ7rH835VUtWAPxPmh6e33jJLyF1LmmYMSv81R50jKqJdkqCI2dDUa1xG ZgI6mJwtnwi4jSOCRs6icJR5XXbuyPOACACV1hrXEVTAXCnkvrB0vZ8FjTqbacS+ 1PI1v77ypPIn95aFn2fn7i8ojYf2MIIBCwYJKoZIhvcNAQcBoIH9BIH6MIH3MIH0 BgsqhkiG9w0BDAoBAqBaMFgwHAYKKoZIhvcNAQwBBTAOBAh05qDI2Ar72QICCAAE OKOQzu+R5I48MSppj8vB6pLOR2z7g54qi3BqyZOeeDe2ACd6O3NfG/PYhBlaf0+3 Ve18P3K7uxS7MYGIMCMGCSqGSIb3DQEJFTEWBBQVCcxtwgFtCxUb3a+xaFqEN8CK ujBhBgkqhkiG9w0BCRQxVB5SAFAASwBDAFMAMQAyACAAKABlAGQAMgA1ADUAMQA5 ACkAIAAtAGsAZQB5AHAAYgBlACAAUABCAEUALQBTAEgAQQAxAC0AUgBDADIALQAx ADIAODAxMCEwCQYFKw4DAhoFAAQU3eBhLahYNnEAfOqstFWLRhkGW64ECIM22J8l 0UAiAgIIAA== -----END PKCS12----- -----BEGIN PKCS12----- MIIDwQIBAzCCA4cGCSqGSIb3DQEHAaCCA3gEggN0MIIDcDCCAl8GCSqGSIb3DQEH BqCCAlAwggJMAgEAMIICRQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQI8DlD f/FkAioCAggAgIICGKfq8w8XKEbdolrBnthXWJAkm8mw8JWavB//y97b4r7HjtPw 0uUvfXbhIRnYNu76tac9zlaH66n1xLLqcUAEK3RdwPLN2qx0hs3vulUV16TVao+U smU65HjazxXC/Oa3lfxAYhlxX44Nfe9p6uCDdf30G4yDKJNNSiuw5K83jpxrlIeH UIGakE7XQ9gmROuOSAXJzmBOjw6rUbBtbUgP/J//yvP9ZeJkB3OFAYhohGo/9ych L0wlk6Md6Vtq0nv/zYQP9PofXzfZUh+rZha3rxKioH7xAhnRNxvgh4mksqTyJM6k OsXZ3rLvxehTKgSm5clEzr/T3qxjTusuNovTlt/avBnpnZIwS1qzTeq0zrd/m7H9 yM6NV7Cbl3LtHzQEQkrJGxVACDc6QcCrmHb7tJBO9dAHiZds7OXlI3QJ4D/aGAru mlKD4ZFp0XurJOu/p6BocEyXo1D0yYEMVoo9/KGH8F4ugwyIQmc0XxrO5mmeRzQk PH1Em4Im4DCKXX0wrlBEPmVuevlh3JmWQ0UEtmMxrhaiQ+Ufjr9TD0Hn7D5wZGVu B5ymH68fPVe/HwksVHIC28uYM4EDMdaKs0BiPRxI5u2jBcWfSlow/jVsK86TcZ2J 4+p2X1949rD9Rz5YKXkaOGnkbkIWAyYDFZF5LW4+jNXxCoo+zloz/CIJmNk3Sn3F v7Ao4VDmb8FANwwLzzYoZ6ZI/KmPMIIBCQYJKoZIhvcNAQcBoIH7BIH4MIH1MIHy BgsqhkiG9w0BDAoBAqBaMFgwHAYKKoZIhvcNAQwBBjAOBAjrE5kdbf4WxwICCAAE OL0cHLqeh5j6Mpts0fF20kwdBzS1/9yXPUtcD+CzwEvFaJCMBpt8s4inBnxN9/vi D7hg66rk27phMYGGMCMGCSqGSIb3DQEJFTEWBBQVCcxtwgFtCxUb3a+xaFqEN8CK ujBfBgkqhkiG9w0BCRQxUh5QAFAASwBDAFMAMQAyACAAKABlAGQAMgA1ADUAMQA5 ACkAIAAtAGsAZQB5AHAAYgBlACAAUABCAEUALQBTAEgAQQAxAC0AUgBDADIALQA0 ADAwMTAhMAkGBSsOAwIaBQAEFKL1V7ctReB15tch/MxfPTTEW0x3BAiQJg8kHcKT 2gICCAA= -----END PKCS12----- cryptostore-0.3.1.0/tests/files/ed25519-public.pem0000644000000000000000000000016107346545000017656 0ustar0000000000000000-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEA9vhO3vjZNz2lLj8wwMUKNjMCm4GdwNDklZLRAvh6MRQ= -----END PUBLIC KEY----- cryptostore-0.3.1.0/tests/files/ed25519-self-signed-cert.pem0000644000000000000000000000101607346545000021533 0ustar0000000000000000-----BEGIN CERTIFICATE----- MIIBVzCCAQmgAwIBAgIUQic3Xx5HxBkV/L1hvf3Jx3np/w8wBQYDK2VwMCExHzAd BgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wHhcNMTgwOTAyMTU1MDUzWhcN MTgxMDAyMTU1MDUzWjAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29t MCowBQYDK2VwAyEA9vhO3vjZNz2lLj8wwMUKNjMCm4GdwNDklZLRAvh6MRSjUzBR MB0GA1UdDgQWBBRXgGnuceTINDGwIQF7nGpBq4EpeDAfBgNVHSMEGDAWgBRXgGnu ceTINDGwIQF7nGpBq4EpeDAPBgNVHRMBAf8EBTADAQH/MAUGAytlcANBAH6FW7MP uE41hJJABnrR+jdkGOzRH+C42g5YgYEKBLFqqGz/82nfX+aaJkVuxPrsjaVhTKHS iCazhjZq/l0njQU= -----END CERTIFICATE----- cryptostore-0.3.1.0/tests/files/ed25519-unencrypted-pkcs8.pem0000644000000000000000000000016707346545000021774 0ustar0000000000000000-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIOrKOPQUqxCUeZnZKJi5EmoEjxnDSSGp45U/t1evy/3v -----END PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ed448-encrypted-pbes1.pem0000644000000000000000000000343007346545000021241 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MG8wGwYJKoZIhvcNAQUDMA4ECFWox81pCznKAgIIAARQzXqhO+QND3jDKs9zv1Kj MNU8LPm/PpazS6ec7qkxavm3P+5IFMk8eQl61ZlzgsZh3mLzERa3PI6bWlZLSe8V 7UHVIpw3KCQcQP42hfAQSTc= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MG8wGwYJKoZIhvcNAQUKMA4ECDioAMUqN3XrAgIIAARQL2hyA+GU61GYy+T1t9aE ImSrEUBls7Xl3Ot4hOiLjOAP6jrZqTV05RD9QQwxZHbRDVq/HX/6A3WK0cWd5LXJ u9UUhF0M4QTSJ2YvgzC8GZU= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MGkwHAYKKoZIhvcNAQwBATAOBAj+fxvGvZUmFgICCAAESR52DDqYruEbDKjnQYPb 4pqdQ98Tenh9F9vWcYvlPHKroHOSrPuW5p0ISNcTMjs6WcwfzrRVRLKMIUwUxyOc j4+KPXziQpkTCeg= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MGkwHAYKKoZIhvcNAQwBAjAOBAifgbGu7z4HxAICCAAESWH3dIM8ezNr3m5cuklg rOFbFNZqS9bNjvRVX2rQ4UsNl1PVNw3cxe9Mg6AYg7mXffibNOVZWwzbYi/8jHv3 f2atBdH64mI2ADg= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MHAwHAYKKoZIhvcNAQwBAzAOBAjiQ6AN6cgfbAICCAAEUNi/xo5EN11/48aKiymw 3iiopFH549Yhzl7h/R8PMkR/73xSokPpShMUFiG9dfBHiJU+JrlCg7oINFK44+R0 YAN8vHdg6gXJHyxQuONZQZ7l -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MHAwHAYKKoZIhvcNAQwBBDAOBAgG3+c8DYCcnwICCAAEUARVfrP73l/qnbQwBVpZ RxBDrm3QT3Xn/VmclpSGcGBurOV8qKO2nYj7WzvY6KOxXVfGsrVuh/uOP7hn9l4L A2KiGc0TM0sa9GGwg7nVWydN -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MHAwHAYKKoZIhvcNAQwBBTAOBAjD/E31ow0hhwICCAAEUIEjJ4SJ9Aa5lUhe3a/q +1sf4bi9tFscXczGy19qKwja3zyisb7A4lFhFFojzN9Xf72qLQZlWerxG/E2xbaI /toDPUlkEqareLJSm30dqltD -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MHAwHAYKKoZIhvcNAQwBBjAOBAgGWbPgRlLvWAICCAAEUBBrF4fOikjttSlIQSyj Uc84dgLgNVoxjSgEw5TFVD1hnHf6IhkDE/ke+sKKn897QzW/8UtLdHwdHBE1F04W BOx5TskfCIfvbw2U6OAFQUK2 -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ed448-encrypted-pbkdf2.pem0000644000000000000000000000413207346545000021377 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIGfMEsGCSqGSIb3DQEFDTA+MCkGCSqGSIb3DQEFDDAcBAgyO4eJgChTHgICCAAw DAYIKoZIhvcNAgkFADARBgUrDgMCBwQIjCW/gTtbGrQEUBOPwmDji8JmdtYKneqP eHoOJVTC4h7EvPI8L69/qCWmdoQwb5FZQ4swhLYhEi6HUzaKF9rmF71SG0yj8x94 Ys5H6aRYf4yJ8mTYq/jNdYKf -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGiME4GCSqGSIb3DQEFDTBBMCkGCSqGSIb3DQEFDDAcBAgPnWL5vcrxMQICCAAw DAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQIk8VyO/qFnksEUDDZtPg1FOH8PvST LKW9GEgmQVzqxYyQPUDVL0EjVbP5TS4Cs/bA/Kx4vX3z312PeY3I8JZtVoBLjWX/ sy3xgpqnGSmuNcvMwWaaWzcYD06F -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGjME8GCSqGSIb3DQEFDTBCMCkGCSqGSIb3DQEFDDAcBAi08Idt7k1mcQICCAAw DAYIKoZIhvcNAgkFADAVBgkqhkiG9n0HQgoECHBod624v49oBFBLW/h5PDwAyvm9 NpmnMEgv1BHHfVpimwOGrHb29zrB8vxNA0h+8Lo0BcSZTpnL8jbN+IRLfBmyy8zx EON4rhK8NS/auC1Wz/a03e4bCtMtGA== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGtMFkGCSqGSIb3DQEFDTBMMCkGCSqGSIb3DQEFDDAcBAiULPupkmkOnQICCAAw DAYIKoZIhvcNAgkFADAfBgsqgwiMmks9AQEBAgQQUeP3K6y6H4/WAYH3t0rKXgRQ +Oo9san10yxV3ZjXi4VJcXiW/efe8T6aomjdLAfKx0hNtnf4YngHtBVyAHPLfI1x 9zWCBTzEt+agp4Umazk59dBhiIB7eiOoNhUZOFvHTtc= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGqMFYGCSqGSIb3DQEFDTBJMCwGCSqGSIb3DQEFDDAfBAiA7abz6Y7GFgICCAAC ARAwDAYIKoZIhvcNAgkFADAZBggqhkiG9w0DAjANAgE6BAiq6CcB7kKwXARQKLMY sHJoPrAEufRO5/iMNEvWbhrOTY1pNnZkryJTfnJSW5mnNYOdTfYFiItrd/ivH5+g yMdFYFBRNDT27J1OBDSJHQQkrXmf+pb966ElVy8= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGrMFcGCSqGSIb3DQEFDTBKMCwGCSqGSIb3DQEFDDAfBAjOvvRIconlRAICCAAC AQUwDAYIKoZIhvcNAgkFADAaBggqhkiG9w0DAjAOAgIAoAQIX+HtJbu7CmEEUAC0 aGZdMCNUA7aBhThDoH4DhK3F+u4TejId5xx00znWPd5lB/yXWJhaK6Rce/+k69oF UUu9NYZnwURQ6SpoMeu7jLRvuasVNDZs9NKPm+MH -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGqMFYGCSqGSIb3DQEFDTBJMCwGCSqGSIb3DQEFDDAfBAgGFmNY/ilxeAICCAAC AQgwDAYIKoZIhvcNAgkFADAZBggqhkiG9w0DAjANAgF4BAggk5ndlY33agRQSd7A aeL5zykrjjIGNEM6DyzjN7ooiAd4qHHC70FkaNQ8RJneqXXxi1nNZDdXhaLa/raU ifdM8M8566L7O/s6N5uKR8W8+ieDlmmwAIZDEGI= -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ed448-encrypted-scrypt.pem0000644000000000000000000000161207346545000021553 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIGjME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAjsra6FzTgntAICQAAC AQgCAQEwHQYJYIZIAWUDBAECBBBBzcngO3oAta7DS9ulmjcgBFB4gmQnHQmI+rbK RFBjSrSrvHGeYzEGZO16iD0bQnPUTwStLE4y4rLE7AvD0/6cjjW9DnvPmPBW26ZT IyWW/JZMykzfM0dk6ccNLg0MHibNcg== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGjME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAgbq3ygXPa8GgICQAAC AQgCAQEwHQYJYIZIAWUDBAEWBBA3IcY5TlZ2FzxzTGljkaVTBFAEJRrLXzngWHUH No+Hq9zGFJ6yBekd403KmlaHCdVPd1JrmgnYoPS7RYxhTMKQ518Zn218Vtf4Pdjl XrN2MQ1O/eiQM1lp4lvw7gt4XImUFA== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGjME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAhoIC6uL0dKvwICQAAC AQgCAQEwHQYJYIZIAWUDBAEqBBA3aL14nbkyRn7MPVVqbgZFBFAY3ogxHUTT8ozS tDmIogHDjazBBs98CIwdwTYrES20oZ41NCezpXlpPVFrzjqHm1rP6ZudloRPUHG/ xSEr1JeEKm5mBGTA1sjRJFyT5Chd2w== -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/ed448-public.pem0000644000000000000000000000022207346545000017506 0ustar0000000000000000-----BEGIN PUBLIC KEY----- MEMwBQYDK2VxAzoAWopNPKAV3+c61CJqDrnMnRntbN8QSNHZwdKEXjxV0q522y9I vhkuuwOJeZpMNqlLL8frTS1ds3SA -----END PUBLIC KEY----- cryptostore-0.3.1.0/tests/files/ed448-self-signed-cert.pem0000644000000000000000000000116307346545000021370 0ustar0000000000000000-----BEGIN CERTIFICATE----- MIIBojCCASKgAwIBAgIUP+cIZ3jsepQ7zNuhZtdcyzaGHa8wBQYDK2VxMCExHzAd BgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wHhcNMTgwOTAyMTU1MDUzWhcN MTgxMDAyMTU1MDUzWjAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29t MEMwBQYDK2VxAzoAWopNPKAV3+c61CJqDrnMnRntbN8QSNHZwdKEXjxV0q522y9I vhkuuwOJeZpMNqlLL8frTS1ds3SAo1MwUTAdBgNVHQ4EFgQUvzGR+t5kH8Ta2XUs KP+uQfMQFUcwHwYDVR0jBBgwFoAUvzGR+t5kH8Ta2XUsKP+uQfMQFUcwDwYDVR0T AQH/BAUwAwEB/zAFBgMrZXEDcwCrI8049W/mjhgaJm79n4Zwb1ryBg8aiFqmvszd pFhGmhU1TWD+qPmBWOIdu0laToDvBiITaLAa94Ck0BZdNFsbqq1FRFXOzsLwV6kW lLwG53nY7ITnC1MVytl8qjA0tsrnHqPwm5pp8rIzJudNk4S+AwA= -----END CERTIFICATE----- cryptostore-0.3.1.0/tests/files/ed448-unencrypted-pkcs8.pem0000644000000000000000000000023407346545000021621 0ustar0000000000000000-----BEGIN PRIVATE KEY----- MEcCAQAwBQYDK2VxBDsEOceJ7Mc21YZq6/qusCHA5d3wARXuJxMKSRkvsyD4GEKq hlubDZL0FQiS3OgjbeuKN+63xa+OVVz9XA== -----END PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/pkcs12-empty-password.pem0000644000000000000000000002520507346545000021511 0ustar0000000000000000The file from encoded in base64: openssl base64 -in alice-nopassword.pfx -----BEGIN PKCS12----- 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 B9A= -----END PKCS12----- A file generated with OpenSSL and encoded in base64: openssl pkcs12 -legacy -export -in tests/files/rsa-self-signed-cert.pem \ -inkey tests/files/rsa-unencrypted-trad.pem -password 'pass:' \ | openssl base64 -----BEGIN PKCS12----- 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 CBx9AR1csYyJAgIIAA== -----END PKCS12----- A file generated by GnuTLS with --empty-password: gnutls-certtool --to-p12 --p12-name=demo \ --load-privkey tests/files/rsa-unencrypted-trad.pem \ --load-certificate tests/files/rsa-self-signed-cert.pem \ --empty-password -----BEGIN PKCS12----- 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 PRSjE7CldboCAigA -----END PKCS12----- A file generated by GnuTLS with --null-password: gnutls-certtool --to-p12 --p12-name=demo \ --load-privkey tests/files/rsa-unencrypted-trad.pem \ --load-certificate tests/files/rsa-self-signed-cert.pem \ --null-password -----BEGIN PKCS12----- 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 nbWw5eZvpVsCAigA -----END PKCS12----- cryptostore-0.3.1.0/tests/files/rsa-encrypted-pbes1.pem0000644000000000000000000001740007346545000021200 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIICoTAbBgkqhkiG9w0BBQMwDgQISh0OTbIn1RoCAggABIICgOWdmj2NX+yOcqMM 1BorzrDCPbRhZHhXRT5N0JCn/+ztezF9DJNRdXODOe7Tmv4fwFwon00R3xTYgHGf OaN+32EWJi7YCYzBxfPbqNt/W5bnpdzg+be2T/zFsddDLSpG/SAaPQl88Njm+6xy XBKP6b/l6CaQIKcuujJCGO1D9znnPGzeho4EjO0usFCG1udGDBeaxTunfYXpllnz 0+TBrtvicNw1V43vTUEmspKo4Qm64gXOfayAaAaHMIJg0s3BapzlK5mUtCFFScsa kFtFMOv8oy/JIfO4CRTq4tle9NRlevYrg2n/DKHhDV8MIrYrHya/zfkV7WylgqT0 3xppLkg6xY/EWiSnZDFj6yNp2Abp2EJ+xzUcjJiVOiKlLFhZSL7k+FbMIYyRIr9l NQfTBHERqxdhj9OsoUMJnvXjrk/55mCkifo3DqbsqlnYlij44GgUPpKupGv/k+Bs Sb0nCOgvBqUv1IoZ5W19rc6LHcvV2XOObJErEJFqLwgHRPbM6F5sNqXymBsYn/Tw N/ZlJsWuj3R7eExb2vDvTSONoirIJA3Hqjytr6r0hLi7lxvTwJ753Mp4uLf0vD1d 6GzD7Un6CIb8eEXYjPP3GatpJDt2Zmx+5FzyRtk0V2EBY8xOCW+Ib9acf86oNGnV EELuDOU/IZPzhq3TUs+D5R/etpaAEcXt4iIzDmVaouOzQE1IO9zDGK9fds/9Wyi6 PRwmJ2WdAE0LK1blHxl2S5IGMY7Sq0ucoEp724X1C2E+HqfeLmQYcpVoJUeiVKzU 2HfYNjmoDLsDEDd+Vc1il1pbXsv1wNdoGjolosK0RFySeuKM75NXrweezoBGKYAx yj4Wp+4= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIICoTAbBgkqhkiG9w0BBQowDgQI4xTr6w09iQUCAggABIICgBSW3zoFMT+RLN2F OH48irzSbCwYuOAxHxBB2uNsAAalagqIyq++/X3Ww9wtMJU5NRlFu2RZ2MGwV6HX C5nOHIXUlg71b5XTUp0RnP+Qi3TP+hAyQhAEHVIdnEUOLIPp9j5SJs+C7NUQUsNr UQExWN/72nBv8wSe0pbKJzCk1ogYMechYXAo6jWnbbvgUheUPG9XJhtl5mW5J1/R uJJP8vrp5TEsVY+8BRkCulOlOaT7TywCwhSoDJG2+nA06wsEhEY7hubLzSvaircl TD63N+CQhTCaIMoVxovG38cI1+fuADCgvKWlMtyhX54cDem/rzk5N9iKtVAqiLP2 cA3w0nkcOBH++FvZLh9nV+yrV60nkhfl6LN+3Cca8qcwyzWgEg3MCcSBGzcPpozC U51Yfd/0jv4yjCCJFh9BKa/GDaEPSWrSfQXEFkbTXlD2e/G9FTMzyYmvU6rK+sVa j3wrCqemBMW1xuGFk1b9UntZ2XgMPShPDlGsgwnegWv90bO1VRsUd+zyUbuggnT0 ZAbFKhPVbkhvlW233MvteRguwQTCL1DlYPo1i2HSc2vmozcxJHPbriEVRJ2QBznU 6Wjz1JGwKjJeNEFDT0jykL6SZNu8tr9VIUxdxkxxIipAj2Z/EDi07TiWJ7L/SsTe 5quEVtjdAxfMBTSfWyF3NRzskypazq8D7y43LMkF88cGjiLVw19WuEd+WWVyhthc /NoALEQb8VaK9wr5U7kXMehOX6pFSMn9s9P4h4Ch25mAGXhv/h0pw7HBZAv1a4o9 3TpghC01SfDCpo7raXui70vMHG4TSFqJa2Odd8apTBReMWRe+U40Q6rxGlw34gk/ J0JqYno= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIICnTAcBgoqhkiG9w0BDAEBMA4ECM6WxHwQYHWoAgIIAASCAnsARgLVpWUcxsM8 i8xKdB0QCGKTBl67KKFwz3gdix/G/g12KxpGFIYb2yv0kE6D9iYBkrQhpdEuLNez K6E5bmyEJRyHVRy0QdmfOca4pq41Q9kq4+6PRvDR7OhtbxxGvsAiFnQYv6BDXMmN iRwDQ8o6R7yjBHTiY+5O36nihjikcurRmHJ3Qv89ZnHw4tg6giTMMVW4wQeuLF6N BKF0jntk2Jbfd0WGlWfp+WFxd6+uLeYa4hN9F5JEnhqVDTbbkWsl9pxIZAEkHY4E 20c45SoVDx6TizIj0xENFnXAj8WlEDepSptzS49IGHTo62FYvndL23Rq3tCBs5hq uhbWcDrIJIggFSyyXB0tLFZmPt9fN+Iu2CeoAleeTPiI53dJUsBM7suZ40R7jae8 9XXEPXcFt+n8iImScR20deyzjr+BJ1oZY1Nr68X4tjkL9cBIR7JvhrMN+lWqhE3P nwBhS2uW5UCH5iTM+dBjFiML4g8FdVPBk4U/G+opDYFp2SVrrVZx0bhPAk+kzqdx q9x9W5dIl+Ck+rC7jUKqmvY84G0QxsQxe/ZZAL18LYOCGi56GkVMbHdOeq1c3nac TdjLYXRyEKDS4XcwyFj329efiYepvXlrhXbg1Vt2VZFYG8ZU2ySuQ4dvC3pWwWH6 rvwTQQaydSe3XMETSGF++fBO8KE3T09ud/wk4oCz/hVRxBD8AoqEzI3HRCF4u3WE LnI4SioONlYdNJlKQ5mX849DzTzTQxH1+J++eYr2Hc02Fwfr7GoapIStvx5mE7v0 VNFxZ1PJt9epHsRWl3+B7qc00uYepLLApOaO+R4LA/edP+gYqDh7ZfweeCZqXfIu 7w== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIICnTAcBgoqhkiG9w0BDAECMA4ECBLMiGMYBQ5qAgIIAASCAnvGBATmzbWlvdAs 0x8+aHrCo5HkzCFwDQkCrvaVn3HZXx09DqK2p4TANA+iaKn2eQwqljuTuXa7cCPh t5ZZSxDnErrXalQrXhAtzTX67tHYkyeaIBOWdvIzRBjQKFUfaN0zS22Itkx0ZTc2 RYWsBXYNe3JwfXP+0RRv7Oyd/Kf1TgINgjr4Lx+T+PykuSh/CAvg7RKJEEpyXJ3a 11UKPuJpK9OeXMGrozpIVTZ4n/jHH8+CtEyZALbh4YbSv10dnXF0UnckKmG9NOya zqX5Um4gKpsgruucrf0aWPrfw0dmKXVEKNHInAWiknswKuG2VgRLoBQ8yoNqGh2y 7btNB67bFSZsTsM/Phhc0UbSGLrsidKV8tnBy/5m2fE2oUTGVkMChVMbKfHtAzey 98fy3t1CikPW+pq+2I823X4UXAHsffHHey6Q0Vyc3t1klPcbhCP2GHVBBE7D8lJs /qS0vxoMJGqAvwpNd/9dPmh1aY4jIBufS4YOuwudT2CpidM01a/sOcZ/u2VYFral OrzYFEVqD+j5A+/g9qMPiUYFduWavCJJJjpyILuDMSCCUkPHkLVTrcieehieiT1t XXUq8EEQQc3pU7l55SUJtDFGj/E7r0BMBXv6WchowzbmRKTw3XM97FlHQBCjAlzy ls+OPQcYfs6Cwo0McKjPSz9RV/G3rb7ROGthsh670OZ+8zD2QjF2rdV2evkor4Oi tM78TfyLqoljmzi+nWR5tJtqIu1aapqrgLmYTKCju5G23gPEhNpJiCZPFtVDgRJi Jnr2EEDIr0Ya4GTjFGuhvMVBxJikKivJtuwxFQv5GJjZigaQ9OUysng0xi2ehuq2 9Q== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIICojAcBgoqhkiG9w0BDAEDMA4ECODLLH2C0BS+AgIIAASCAoAEF7rmVky5iuWg DWTT8y8r4TXJ861WQVo2wafDh3CMqIdFINTEHotenQf8lR8OOTwpQgvnYefO9vzS vs5bYYfx56Teb2kl7UDUIpcTyHoAKDqQ30G/b0Wp9xuX9XHxx3dX/ulKasjhDk/1 yeMrj9elZ25/Q+zpmwcMcY0eht/9JjA/VwWmqqjys+QxypfNtfM60yffYKhTZl2R /Y6FNSxAN+zIwl/xqxITSXuqnz2XqR3IMthS+ZWsiAgGaAvh6Fvb+43k1zraGOdv I5axvmDJV/nNkq74VEakFlDBEckSgNOf4d2dcmiBt0vy4ASdNC7Tv+3hQlmmXN4Y tWMaY4pgPQOThvFlG/5ukSmEKBYMxIZzWUNDZS870Z9ceNmbp+UnyGD8YkjbmmQL 1WGT3TF/33NdHpLy3MRy0ASTxzYfvYTRgkWnfpzGR5gsOVu2D7UeXbjzcJPkTHZK k8ZiQ8v6ACtDxCx2OupGbOVcAywnLP9u8wQYDUPLTq/TdeoBm1W46HmDqQwA/VPL YIbl0p44ha5plhtxIWN+fan/asGRBBf2pHCF8dBgCGj0X77fYSeuq5o7fYn5wVUx KaLR0g4F13ji1LHzuzNF11WA79msHpVUNIK3YTKFk7l6Rup0fSRSGJZUSQg/TbP7 O9rwkEcliugCM8BGUibs5ZcQfpHELQNA5QHgVWBC2Lp39uP4OSjKDdX4MsKuPhBi ii1e/xDrSKoVrwJjnb/elKoaFNIczMBn4PD82qI2sARCfLC/zju6WLnfEeA7F8FT zhVZ0L08/I/EmWZueDok/UTwoR96l5ED4TUhl/f1PdChw//wxXqTmnf8FM9x9u6j ussjx7C0 -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIICojAcBgoqhkiG9w0BDAEEMA4ECBavQC1n+uBBAgIIAASCAoAcCG+qBemh0n12 3dgUZr9MN3TzGYIr6qeL0puLn61FAmRj8kQzvIzCgL5WOUtnhzktkWZO0oHkz6Wy 3MU+AMi3pjnFJ9dod7/UBbnjsoEZ89gqXc1CkvtKcgETOgGxuueHT8Xi65PwS8ss 1qiks/YX4FinIrFk97VOVR3/jd4gH+bMK2cMaMWy7GLUIVgEGYuaa1Fe/lIPkpyb 07OeBaJ6bkhRf5dhTl8CIkKhsW1vLUkbVN7c+JrBeQfIw2C9qEc3DrepEXFa5Zj+ Cub9EJATUdYmCXq/bc05l7dVrUmZWkSh6VKJSuC8XlCJaYMCW/ok2JwQzPmB/m92 uWOQtjxhyKZ7BdKEAFppNxPQA2+rgQYVBQ1erJemAw75fQF+izU47LCr+u80jgWD TSdxMxxuOjoFQaDu+1/j6gZBcK8ktYNn/wUPZYfir90pgmAu6S6yoM7gSn7A2X6f Gqg25zPJLAY7CRWLBPRcHPUau8S6M4mH0Y8/ohhcOpcUraunIrB029eWzm0ll62S TxL40775YOLZ6+1K/BtW9ZAcTodLb0j5jBVAMujxKWFKNz4sgs4KmxkjmFEo5FjF 6QvX2OGg0HLwJtEtb8Q8B2L0z661jNysqbP8n+thZfNvgzYGGl1Qfuw5sdpnunQv rJygKIamLhl6vCCA7BAyzB7cjKWxPYFoNzM2yEVJ8/eAtrYowSisGt8QJQJhO6aI IICAgD519C1KLIhRuUP71SCudUZRSGlaVIiAwOv3Gx0cxDysDIdF/hwZfHoJWt96 xoqgp1isV9eac0dzVKZ3rQFoDBjQ2j5wCAB6/MZP0Vgv+Ipx+uhrBOmvCMzdxh2F vf21uloR -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIICojAcBgoqhkiG9w0BDAEFMA4ECHtGUce8opaaAgIIAASCAoBqigpolvtZWgII AMSQNceoXlu2Lz0RJaCEouVe73ACMwcnDqrGD8vEt88+sJs+hgee2wqjXJKKVmyO KuA9wtl09z7mCfcPAmGe11P6PZ7N4rdxYGR7URqQPsD7iD+S3v3CLlSnYCJnY6Np x/j4Cfc2OIH90Vb8gxT5xUbF3Fnt459yyDnOxJoxSxD7pIv2SJqw/TD2gxPO/j6B mdbKTMubL0laDraoBLQi35GMpd9Z9HkyNKCxuk1Bw1ApUmXaaf8dWOxkk/5LIzge 24eCOp445zoktbpN+Te+osHan7ZILte0bf6r2D2zAS9gFgx/xJHDeLcCYmbM8FCD msygHM/rqllpj9ztjwbpsnUVpLGb0WP+mx7XWGDxRG6aOlStFw1z5vC3cvBqG6Vc T0WW+xWcVxMHzVjQXkb2K7RUiVTq9DXQmq5cs6VA14InkulMXmGtaqFO8jrPOXO8 vdauxVRrjpzZFuGprCN3gK0/rpZ6rk0i0pPJ3PRKw7OXsnHXSwzGljtP0RbBGpBq zq+5DIgfhLVHe62TFbqCKguvZIY+8To/tm+1ncu/unt4xhLZp3lnXZ8DeDUfwmps e6RT8hXIEeibFy7/nG1lnt3KfMgKlLA+F1nDZyv+s6T2/IWOn5i0z4jwkfSQr3ND e8b3AYukHZwgqae7mYw5T/SnMo19A2A4Hj7qmKVzzK5p+P5mOU6s8CEdQcgsDvBG geAArOaRkSwL+n/AA/1gjuHbmkF++hRhlto47rUui+mRWU0O9CeUExks1cL7wqEG VVB4JfLBXyqZpjNyIqfiv5TXqhY84yOwuIXd5K6FUCRjNa1w/NijwBk3qZ6viCNM qja7N3Wj -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIICojAcBgoqhkiG9w0BDAEGMA4ECPDymiJgHpERAgIIAASCAoCu4qQpIS8wXbgn eaJB169bcoog3uWtwDKOrmfH38M7aVwOW3WEK7vvv9a1MCarWXUFVqh44WAKppx+ t5ZQto49prXEHu2DhJn19Cj6bG7nd2E2OHmnzGjwqgm6CIJTjFvPNRQZ3eS1dymO kM8sDBo4Sq6AhMSg0Y8S8PselzVqklLFXzXJGzJDSLpvpxoVNsqqXGq12sKvQbcZ JTAsydHG9OJhOvlku/FfFQvBQY7tw58+UhuoxDtLVV78zhFJ8dYswgBZpYMFbP27 HKJtsv/x1Jg+Rv3l2AN5kgoUJ4oH8Ow85PzaDBiojAtk1/mENzBG9V6HHm9rrCnP QeX9G4gFuyIfV6MJa8D+D8DeE9tBMWeD9j2d3zsibBDfslPR6JnjrIeDPAvZhgMC wzNkJ0Lrbz3j1l72GbDDdp45a5nVQYXpyOPYfCv+EgyUC6wHIUZiFnpae5g/184y vAMkiv8/7vXK+/DqXmu80yMb/EiVrmmrn5q3CmTfuNiq/NnlcADXcYOieFG8P8rE 6rGoyD8JXJcZEG51aOrE4xCVWRP8SvASuaYkJmku79wRlh3hnuRjsj30pkWYPCtA P3MKaoagh1NdDHflsmap7U5m0A7gGZ49/c6X0vk7H+PKBsQ+97UTza6oCVTY1vOF /S+GdwtsOxeQlMBtY2UGa7b5RUzZUVV+HgM/0Wy5ry5Yk3igJxh3+7pp4pzxCgjK OlATWZnbeG8M5V5VGNfztckYm9VouW75YatIhFhN2tlB5zI4cnlns4PD5SBxdKGf YC7qdy+5AZ1aOv2AfD60jz6asSeFGq1RQHOubprTOMUTTmVDv4Li9zcuS1Zd37Vy kGbbsAyZ -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/rsa-encrypted-pbkdf2.pem0000644000000000000000000001647207346545000021346 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIC0TBLBgkqhkiG9w0BBQ0wPjApBgkqhkiG9w0BBQwwHAQIYhESCE5rdlgCAggA MAwGCCqGSIb3DQIJBQAwEQYFKw4DAgcECBJVswj5JKmLBIICgPNcarPhUgPzqAFF xb8LvwWSW6ES0QTM4d+/JydSSoBX/UHW95efGhrUOVqRTuuxyPvlEepMBsqHwfur C3IlOl3LayZ+vkbbkevt0fbb/pYxlDkUqefa7q9L+VJ52KyWRhrSytn/nvoP4Ptz zlYf9C15dPBg8oKHYxrKThhN55kJXoJvJk+kCCuun2sGECePhy4gRpAhxKYiI68G oSWUe9PisHdO+VbEbF310JlRWPHq22kYfjN8rEkNVBvW2WSMLFkMfTGwAxQStz8A n9sxmIKMuB9qXKin0XlnekByl/ZZdXdxIYmZw28627L3Y5SZM0YwvHDY4ZHbIhXB 1iiFAabQBSw/1HMn3Pf5wSikBUmfRPZ669h6F1+B4yDh9pF6qoz2bZR1f+1n3Hfh BYlMq7icwhJukJOJX+GnILl5JkqLkM4kUufZGoBbcfaB2WC85nAgVEggNj40H6E1 1HqiKTNu38FWnUsF4mez2urGS3R+o6bCXyOOEoLwfdqNCSY2PVMBRYyTMtkfj7Do daC/zQBlal5+GrqiyJfgHAUJA0MkZHg1wB01nRSXadSjhMqbn4FVxDbd1ZjGlCgv DggNqs5u6J6vg6CXnu4SN4MGIAJS8l3epbYIKmu3//+0ujD7Iy60HPeReABj2Tnj E6ehImW9RdbAo6dZBOO2m+DHpdo9KwjHakNZ9Tg8vTj9I4Qw7wUVFHZ8mYxe1IKx mi5KH2LvOdcaYZJobWDvGip8hjzF94MZrH/ZOXBULfgQd5nL2mzex54q6BvGD3U9 GpbPDeOcUZsXiqxaA4RufI92YKX88PX14XanF/J+Zq3Fk8qbEzTcOebH5YHm3YPP Y46cGxA= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIC1DBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIyjzOM682NvICAggA MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECPX4T6nk9ZThBIICgEhpSFw+iHX3 d1i1P+Nr6clbNmpjcOGjpoav0IgZDcFQd+bKnOAAR4IEdJVXCUGOdu0Sb1wDTsR1 W3cr//6V3HeiaDbzSDi910S8IgYyuYhnFAFdw/FHoaO5K67+vhaedhV3Vhhio7xv ZNWsaiH86ulFpc9GNOxc+DQK0CYd5KcmJA4wMVu4zEZ6uk0k5bV99UueHBBK7mBB my7QmpvLpSZi0v3Q9oWP6d9mGyixsmER83vmnCr92cmq9HU95OZl5Ach6WsdDn5E 4SeyfZMS62/xqIXf5qyYvPgJ3vyzxIGJDB1v8lboQ4YZrcSKWZ3RyKDx0Wsj9fgA JJxWYtj9Ukglz4md6Q7kuKpd4lwL48Xp7/voliri0Y5NsfFBOqG9KwxcC/bQe0H0 vcvDrLZOiC6J/IGSxterbl2etVRrzeUl9HGJhUyHpjMLUw2UmA3PUHnCZH6dPMdK S12JpEqVq+7mkYXJH1Y0eAR0Nc68exYnB69SCT8yBQ0Z82FvhY/NwGVgfDMMAO2d rieVuMf50hztcDJ9sYTnfQNtf+0mPn3b1SqT6bgAuPBcumS+RkqNSJkmriQWFsjF yDIwpXgEh+k/HJ9rhMJP9dpoLbHjQFEi1AYW1pX4Gyt0H9YkwZXLiPO4ymDttLBo z9DqDX3bbbbPopNuA7a23LxE9yzj7BfZhfh/kiqCpvfE9R2H+pcPJNraJY9A7lLt mEJmCGYRg+lA7uCSTbuuQkuK9wgz4oD3U89CVuEmh7+m8SK02KDxAgk9dONcAIaE FhUIBTVhQqhTwxoEWrC5XSarURpJY8iwe6PckfwLUgEAqGwADHKF+wwyCgCgw0sA HaOr66k6iWk= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIC1TBPBgkqhkiG9w0BBQ0wQjApBgkqhkiG9w0BBQwwHAQI0IWpzTmYNqcCAggA MAwGCCqGSIb3DQIJBQAwFQYJKoZIhvZ9B0IKBAikzaHZjD8DlwSCAoC8h8+cuolP hfAj9NJcfnQHpKoMZiTeTpu2Qu2zYuzkfwjUSjJ76lK3M1gj15gllieTGVM1BUTC nB0isUuIN81Zhuj3Gja2iz+y/BEX/CCfuRXkl/sv3Z5USk6RHPLlJOA5HwNNDTnx CSXlZHqBXIQdqWM2qq3ADC9IM/JsC5QkA05rStL151wep9jOgNJMn6F6NzOWpd89 DJfVAyiUlSnjySHIVjlBtTkmrBz7pF7uNnwIIXPTFx21i4RjDuuRLF1DHvGkO6Yj +ftnpGOPRBoDuyfSVyWkiPzd3N4Hyuw/4LBGrODYJ+QggrCiFgebZ+W4K2NNAAD5 LMWsnsd+zXYXl702z0PwRdzHg2R/Qk3MHq+0tiqxcVsRJ7ZtbXDHZT27yMe6NclO 5WYXgQjWIYddThf5cCzkud3uee0kgAnYHN5FWX1JsGGG+3GtsClLw2HcyrcFBDeG KcAVrJjX4sLO/JFr5awOY6WGyopKC84MM144nqhSirhotv7s3DoVywkG7aHuggqA On+G+FE2vBxlxAQImuX1TZhvSXo/OTO//Id9NBInb8hMrbsOL6esztuXcdmTO0S/ DcjrrCApow9TtFvtCCscwesDnljSM60MP4kMldzJAUOMgZPwD3gWzF9OnSVl3Slg GZk9OFXXscQVhhl+hNQ2rD0ea0N2dd08oPwS1fChv8uYJEju2D3x7GqK0hSceps2 OnOgClrTby0wY5CvOwP6dlBA7KGNuqzp/zGmGciXDJ86TiSO8/L/cJzkEhYyOidX nPY5eGpf2LdMdBTkRvQxqFA4AUEh0qnCe4jyMkaGenAg+B/w9IIjSX8WBsmKKQvW xO58a7/TqwVZ -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIC3zBZBgkqhkiG9w0BBQ0wTDApBgkqhkiG9w0BBQwwHAQIbkqrr8tMrPoCAggA MAwGCCqGSIb3DQIJBQAwHwYLKoMIjJpLPQEBAQIEEHN1IWKxGrmHi027/+3DgUEE ggKAnK7ietFdSKlL38/wpgt6wT9Ef/xtpbFL+y835tgJc1WQR5WDdCcuclJunqcU H3wJF84VXiNg/jpLj47iDtGU65X5iF4Aj9KWppU4IVkz7XbLclXwBGTZMN6i4Uvx DzqeiDPGk36J5HpqntfmwrPLGQi+ua+vfWEoFQWOBweTxF9ROLIFtcZqF6Vs+rpp gOvsqDFVYJG9WUDFwYkF8fLbH69paGw6lxHTblXiACNYPx8uesBJ42LHKxuivEeW dTwqUw/VYfo20Xwih35q6LBo8eCA/NYzVUjGwcH9X3aeSRgEfN384X7HO2Vb2OcA v5XxE//F4IH7iOBwnW6MpIU6yQkwp5ZnT07hZ1XVTu0r8NZbRoTK2slKVdRUO5ND /RuO1JhOU+xzGZb0tUgZm8ns+pjES8HN7yg617ZrxX92e4bBICc7Ntp4IrQdVL0A lqkeyxjFKkjjPJvM19u4I18DDPprdeJcYTRRa9JHRC4v2lprLeKT0euA+ph4I+HN pGhKwzhTsVVt+L7DYGxoA+SxsVvMPc4aCI02GRbHuwbzk00Z13DKegu76C1g3ZXl JRNZUswwNMzJvkaTXyAOEXIEDGft2TesaRtHvJFKmfokd3bM/a14xYvd3CpttrfR iJDzXAyRtsd1iQEvQu29dkLdd5lfIfO5AaiTPfj+7WRH5QpwrBp2yTXi7zWSV7GO BwAujbHcfU1H2vNTvPcBWjebWfaACDcLrxqW4Nye6+hxg9fza9+JqTMP4FOwkf9d /Y97X5I1X1ryDrVb3BqGbkPjDIo7g+ge61nOP44jPMYXzcu+/OftUfZeToVvAtoI I4NBsV5UiN260PlkDbdhoMhkiQ== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIC3DBWBgkqhkiG9w0BBQ0wSTAsBgkqhkiG9w0BBQwwHwQI81JVAGsb74cCAggA AgEQMAwGCCqGSIb3DQIJBQAwGQYIKoZIhvcNAwIwDQIBOgQIZaJ0tVV5iKIEggKA MC8pz7F7obdiPp5xZG8ygIO/G5rV85eRjK/DHnY6fU3mJ21B4oSz8LHE9U1APpCn +AlnYvILP0IYHrUGG21ZaWvO8UzmxefXIsroBFNdO6Q/8Yft4m0PsVKCmiMW+Rpz 5ejsoqxJoBRIHi0GP9uhf4R8UKzLw19Qb1jwjEIYmBLD7OEgn7trwIT1ZwF4TBML aUKlm/Fixri85ePq2eRMYWn/Y30lI7MYyp5Cuh9ynK0hhBUc3pvvE4dmSgLlZUUJ g2IC+U2MKepW8bHUMdUXxaKFva4/qB6vrhtKOiiE8MAK++OC4IhKtl2dNN9nTLqF nm1Vhk/DLqVs4hnnQuq38ixl3mCjG8JKFJKJMeknfTY9c8mqf2s1RhIoSX5jM7GP PehE4AGzRHxg/x6OIVQd2grwJwJY60uf4eapKHbNlUDeaAZ5LYyqveHV9uzPJy8g t4hKYFCplyZfVsrtVjwGIUABxEN/l24HHwRwIulzAA9MuLMBsiU98uK9pXQk9Zkl yaOkFh1G4GrlkOkkPFh6MbNjw6gZBF6t69rQROtNSxtm7hDyl/kZ0tgtU948B4q2 oCxfT7LicHCn/ms9g4xTl3iOn5Xrw/uXjNKNgRKtyaQ/6NZQ52JqMczzHsXRyZ44 LioKsKlBD4kyMZkNmvRI3Uz/xbM4/lm/34+ntLkAJ6SeUr8ui/XznjD37VOco7oJ LMhQZwmzP+GNrK/xBTcw8PpQ+Iz9fyfxYizZ9GyZGAaBHXslupANad9dXSCefOsJ PFRkbiCFmfkDMDeZPdodAnvV+5u7fQvI5GKwXop/M3rLXdtr2l+zAUp/LLn7Sg7d I9AhucG2q8VGflF3MRVUrA== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIC3TBXBgkqhkiG9w0BBQ0wSjAsBgkqhkiG9w0BBQwwHwQIQq9ZzQ+fElUCAggA AgEFMAwGCCqGSIb3DQIJBQAwGgYIKoZIhvcNAwIwDgICAKAECL861DXfO+9xBIIC gKqP9tLx2sQmVIGdj9SPeI7jfY8XtYUAg3UBY8QSM2zeN+TL3cb/kEdWGsVDjUGz meOwB4ap/pQjR2OsfBktztwhmaM2g+ykecxm3Q9X94Ykfs4lbXFDwueAJ0BGGEsx /TLq3V3DGDXwfU2R6wW0eoY6cFNZfpmpzLCX9I24OzZG6kWOQU7wgTzN42SVJCnd bkmclJd1ftgZa7weJA0rI8m4WV24WUY7q//wki9m0f7FMh/xrKcjqV3tdJ1bCO2g Y535Bbj6E7iqvh3Zn9kX+jKTkuUAPr/dY3t2p+eGp9xHJtB7Gt+Qcf2L0q3eerd+ Oh0kV2ww+W8w+ukNAtGaW2La1SmJCbWKE+xgX4kyFDrMvlHjSJcVz5wgm4UarXet vfnlKSvcs6Cm2cLC+Wbl4jcsGjvgAA6Cnp3zhfmVN30eHviZuAwFrr4bOn/EMQgy l9FNAvCRvK5RpuBtu0nZh59zSD/aZ6OXmBOgpuYIKmBLrRnav3NjGpl2sP0M7HEg ruZEgfaqt9xkm264TfA8nmux/D5pE0OayeoO0RiSvmgJlHlr2wLjh5CqCXaa4Qx0 afyN4H+WGngTm10EdA6SkEz01gLPfK2XNZzM/tWWEFS77kNruQ0XU26mdMxplUzS oF2Xi4SpY/2nIz+ZJChTF4NkLk+VRrZr2qp0J/ig/LGy7ScPDrzZYWql/2+mWqXy ai8DFt5wsuuJHohUvidA/sVdm6z/S5qqUJjoxwA20mYontx1lvYo2eVS8XJJhPpd aCM24EQdCkcZ/vEBakEmCWMjoDUfPFC4hdQ7rHichpJSapoCuMgaP0AbN+5FTFCX Tx/WJpHtdpYyx013dr5GvYU= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIC3DBWBgkqhkiG9w0BBQ0wSTAsBgkqhkiG9w0BBQwwHwQIGxaTRI/wuwACAggA AgEIMAwGCCqGSIb3DQIJBQAwGQYIKoZIhvcNAwIwDQIBeAQISj208H4LOA0EggKA kL783AgZq5s8Wa+MG9nlbq4Puc6EhMzW0Nm/EcMl+eydC4UZRiS6gVT1Bn3H6Ayy g4EcOsFQF/iHLgs1hlQTant/jWtAxlporfUzxddNReqrWUje1xl6lW4Kd1vPwcuG CU5RWphp6XsEiJWV8f3d+j99c5Jj2BRKiSPmS+CHeGQlVaSABkDqOixFjQf8rOwP iwTXppqnGbOEkhzRvR0O/K1S+/5ugw4OumzysjPI35hZuk8S5Dp2kpT+ywVqJ0UC uZOL4kykmu5OL+Yhx4SNlME8jlG2nZnf/VvPAe6Yq7RtwwxVwTPL4LtoEmUQWept MUu7XdA29KghHGrWlPoVGrbfnq+1P9xHlYQs4ZYQU5MTqXvqaIO+Ewbxkjhn31jZ 17AWfNKiAym7fVQeM8epJt0SHx92m3MY9ssdbfnrkXFPm5zk0d81LP3Tz7Pcu1Sf ejAmOAHmfl7Bd+23k2VH0QqKVEKanNJX2F7KrK4YOCz4+jritxJIAoro+1DgpnWR kEe1UgguiRcsL0ZPXjf81ch6OKaWR/yUkanRdANx4+0g/lyrSFQtY3XRwFbBRvpV O1mvs0OQRZZBPyH08H92lRdoNolEDbcqN337mUZzEqy9e5w+kC8qoZC2t0P5BDcw bYDORuJRIldYCafK46HUceyenv/1trObRFxD4fZU+GzZaXAfMqCrjRBfRUgJ2kPy QEW9rSqBbqZhQmEg2jJNtVY/GnzvY9F534r0kal3mEA33pCmPf61CPvlSuZB7owN 9J8DSvft0sN+8BkaGCBEwKS6szjE8P92ezD1rH6Qo6N2p3JGzmg6GwAvVYX4vqVk RGdqREJ8fe0tz9JmPaVl/Q== -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/rsa-encrypted-scrypt.pem0000644000000000000000000000616207346545000021515 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIC1TBPBgkqhkiG9w0BBQ0wQjAhBgkrBgEEAdpHBAswFAQIzVHEuZIqTxYCAkAA AgEIAgEBMB0GCWCGSAFlAwQBAgQQdFzY/Ib4OkmYCNavZTrqQwSCAoCMD9qTDZO5 328dyE3+t5FuiUj2ei6u6ibPTa+o2q2WtwnnLSzgRXegAxyy++X0JQK+8Ky3XLFb hjXLTlvNm2mGgAgjcuvEAZQvkB5/oB5epYqk78Nup7EQUcLiG6mV81E4EJ2CDaJI qdsHUfo7RLnjF4AIu51OZD/hngEYxFGFPgxwqgPW+5vbEbNwMVcQarOLt7qWCmMR RSe8EJBFJNi7zwxgdM9+zg+1BSiBvo1vERinIhjlHz+YOc1Squ40dDIC1VZkL2/V BvGWKfuE8/niVgoT7uPBIhlg/03Binn1GexmrNRLV+bwZsVrkmXxwNBLt6XIQrAR ciPmCnRI8DRA2xMpQrKYHYdIE0zcA9381tsLy6MWd1fN/5AOJsdJyL1ssY//BfNU eUkhah80sQrJ54HUIkvX1SGY0z/+Xc641LOlPLZb7p+t2gHYAkuY1GIRthFrAhDN SKkU/P5R14XZgILyTDxcpTfZDiQsil6Pw1WD1M4W8A8tLFpaGqTGN6wtifM7ZpNH JPvZdkOBB1EB6c0lKbUQ3Qg7tYBlPoUl0n6IIGk3HuYxmruMiojugXLkwAFPA2K+ vPFIiLHa6hWy0YpVv3A5Ta5fiDSo+YMWPTEeiuiry+UVP49Y8voS5WEmuauNORXh ZI2pnJqWvB4GhlUEcERYNgpWZt+Z6L+Saq3NR/u4NA1mO27DAJ15adTimg+r9Ipl 5gg+ArChpsDbnr372Wx8kZgnJDGS9H/0BuhOPvhIK+sic1gjDRvMhums4+sPas9T 128lfP3eaiHaFnbuzJEyKe7y9hNcktP11d8P0tQOEXmz2cyRtYj3XenaDyRGh65u AvCqLxjvemyO -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIC1TBPBgkqhkiG9w0BBQ0wQjAhBgkrBgEEAdpHBAswFAQIXyMMZMH+v6ACAkAA AgEIAgEBMB0GCWCGSAFlAwQBFgQQ9/sPlmVc8PwQ7qCji74yfwSCAoClNM8rzEcQ fSZ1xQHUTAyKBhHD+aCz1kZgsCQXGRlpIgbpoI6HorSRXj/piQFoT/lvAlbGoy6D n/7b8a8IS7jUhpfywS3vt6/J+d7LhYZ7pUOEKyoor4d6csUKFJE0D3hF8E4/hCmW Zor9fYTAFQcwAwNtfocShkWCfFz8+jPluDpdjAsuPltRUZfM3fTPH/L7inDmEnuc G+nwMMp0w2EQKNNTj+HvPgWXcHcIPYHd10TFJUO9n2JZsSHZ/6YuByudtAlhEBcM AvysRJyqDTV30Xi07EG1az14tlm09dO9fObpX4v7jppREiHUXd/ypWCwGVMTyat+ UnOfKbjRFy3G1qQNj0K6TkI+4EumP6+oSB/YEiLoN60b1ZbagbAPyhbarlmJuSyN MJbq9YLkofDJQ3aktHpoI2+VDV9o9dqxKsktEEpJPcwKd2W8WGneObACs52LTKNQ e6uGZhs4BdRbNlw53p9YdhIye7W4B4NNW18S3ZpIacCMqZJ2D48HFwWQzmTCaipG tswpQIyD2Jb9NSBrie8Fa+P82RuLuVV8qgJYM38Mtd+dAEavdvagrNoKcL7teqSu CBjP2GTcTrciJXoS0DDakFQMe2z5X1UD/qmDEJV1RmRRSCxYGeV2bT53JyFNQEAZ ZWsZRZ8jFCBVjV/LB41/0+Zbqxj7OmTOxxL3g3hyZ4E+N2ACIUZJxH9It0PNQ3Kz Kik7fuCafPe/oI4Zb9RRjbW6MS3Ku4J/DDPO193xTqfi/faMhmplAhuVDv0z+hlD aZmr4VFFsQJWou0mCecIaY4K1JVS5QlIw92DHUB4C0BXH0SOYLbuiCd9m4t4eZXu DPkUa2DBSaSi -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIIC1TBPBgkqhkiG9w0BBQ0wQjAhBgkrBgEEAdpHBAswFAQId0JVgBVSslsCAkAA AgEIAgEBMB0GCWCGSAFlAwQBKgQQlJjxBqYK7Pwam8z2xY71LwSCAoBdu+1EInkY gLgAE/Kj052Uhmt4VfRgSKhH7mdyrqwO/sJ1hprIgndjoIdNxKDJIYn2GBOJ6eh8 134NL1HTyicnP3umstphxawzl4EbHQLtRjIlde1sEgJR47BeEE8evjB2EWD3cUbT qbPK1vkl2/KKO2muUEbKbn89ASXikRBXasT6EwY4mL+7LZzuqkrkGRZg2xXSPtYp NVxcL5JQMtyC/gbJJ+WH2PvgZVIGupiIdUoVcWmY1rm6Z1zyj+fuUF8Q5uOZN4BR ic5to3X/wHSEqzApYz6wo1Tioy0OPUnlr2WODKGZ+mJK9N8YetSqQ8HzkGaZ+O+1 G8QsTYmitHZNdNK9o0xZJF1nbly50+AqOEF28/nzfcgmE3+qQWJW/lD4OMisbyvF VLF0EEFGtpg9+zNP6edq8zQMqvOM59NHfpy8eh2RemNwIVvupM2xiuS/xAztbJXs 21cQP51GLE2deaoDn/nmpa5cLOfIvO6Ni9Sv6Rp1yIGAl1hBZZEpR9GhCXg19wAa lUFqLzgrjWPBESEAJW30iD6SbQLs8MRf9tTEa79IimnNplkqvMieGgeCZ3EgZqnH D6KZ5S5aPkR8EV7AMOFEFLVCr3JwrhH0NGR6f/nqf53g2uviNNHsbNZkUJwsDn76 /TzaRPLr4LcAG6i9+frvrVPEaS/75/QJrsSH93RGs9AaVzd2KPct/dDByQbpbMPb /eN27m9/8x+4X3Qb7JIPRxbvtjBR03lntBFrE/yxMdAYQt1GdOkPv+n754KDIlhC 6+Z7HJuYkS+QJ1EkAnKG4Y6vnUes75HV7313DlPhTyvtdHyBy8yTTnzma33Gj2sp 7IXtX/S0i79O -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/rsa-pkcs12.pem0000644000000000000000000006715307346545000017310 0ustar0000000000000000-----BEGIN PKCS12----- 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 IAAoAHIAcwBhACkAIAAtAG4AbwBtAGEAYw== -----END PKCS12----- -----BEGIN PKCS12----- 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 -----END PKCS12----- -----BEGIN PKCS12----- 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 Qbe5Scqyes+V0blmkYcECOYC+UPng6RsAgIIAA== -----END PKCS12----- -----BEGIN PKCS12----- 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 -----END PKCS12----- -----BEGIN PKCS12----- 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 -----END PKCS12----- -----BEGIN PKCS12----- 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 -----END PKCS12----- -----BEGIN PKCS12----- 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 RUFHBwJNlAICCAA= -----END PKCS12----- -----BEGIN PKCS12----- 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 bFxutU4CAggA -----END PKCS12----- -----BEGIN PKCS12----- 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 AgICCAA= -----END PKCS12----- -----BEGIN PKCS12----- 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 -----END PKCS12----- -----BEGIN PKCS12----- MIIGxQIBAzCCBosGCSqGSIb3DQEHAaCCBnwEggZ4MIIGdDCCAxcGCSqGSIb3DQEH BqCCAwgwggMEAgEAMIIC/QYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIucFx TNjMCVMCAggAgIIC0PUROXrifRea+3qUIj+5Wwj22vfa0hYOOo9roE3Hu0ixGowk c+as3nzgl9BWyQ0t+VC1sHtT5chcQmWsZ1ppnszRY5pY671gey5Lp54YWycrIxno bsI7Tc/3Qd/vjeexfU17zfuOFesX/PGLczj/Nh10enio6iPvlQYhVSD+5qLj4rrY 9iSRdiGRsQ5chjel1W/jKO9dKzvRoVGS+wzoju43nvQaKzI9YYZkJQi4lMxuxMXr 76sKV8V4lyKvu/57OYEWxuKNUlGOVo60gziV9dzZH1wM9N/SEpxfznkFVC9mgx4y FrIsBunFwe1M/9bPvYGFY9fET4hCCRGLK3FA5tL6c5DgZzlCk1zk4tZuFSiyMbcP qvyfrTK5jNZWoWQI814xIk+HiUDgVIPuFDUWQ59dTVhUbyrXuBgIfqToXss97+Kr idqLcEB/Gl0BPrRTWD5v/EJLUun0JXDQUSoGzzzJdCrrhnhjqZGtSUhvZx4N2GB/ lbgOAFCBZORjIyU179sj6nwx8kzedM175cqdWYJtPjTMCHZKbSx55ItdT8Be6hBb quFcDayTUWJJ6nZflVXXJhsJ2GNsUTXFZCKTgWVNw5D8ivBOUQ9O+e0pmkFZSJMr ePwUAsqgw4KMKFij/JvRZIBld2h/r0pEwiGb5nzNNN8CSvZGFSGdt9AXXMKdJL8h jV2hAhfv5XXAJzDlrvKwAambFlxCwf/NzWjvggNtIOlcGCa5aNEaji/EHK+TuR/g sJFta4m8cVgfoBP6VcG25AeNuQFsAIyMV5wov4r2HpFPozuoF90BbcFIdKGCRrLV ki2EKSXkQYlQhV1NJsBjDLD83vFoNgd7OMKOjjOeFW8cLIadhGR/KToB57cwBFjK O6eLPjtYHFxy315K0xjVB/z7TfzrDbFrZWSoYdB/VuCmYzzqerP96rPMt51UcG0v 6iQPm765LZkGPGjcqTCCA1UGCSqGSIb3DQEHAaCCA0YEggNCMIIDPjCCAzoGCyqG SIb3DQEMCgECoIICpjCCAqIwHAYKKoZIhvcNAQwBBTAOBAgpG1tZ6N3aXAICCAAE ggKAUwVXTIxnFSF+kvkP6VVHGfsXh6cH2mIs5BJtoXt16rKFO+Dj4uDdIgVka5bU fEfcDtrGe+qEe6x/71Vg1rr+GwH7pcU/byKfq4ANr9T/e6s6SUkWoAICzdLwGeAw rFh105/M13gjOu6EpEtCIJ+1RjjJbIA7/0fEITd6LQRPeG7+bhvXpzm9q6HjHlKL pYnh+umiQyeqK8rt4YpnOvRHW/GytB3ABFebtx6WXIzsJVSy7XQrtx509eu/xXOr KpQ7SHSZei65+DXnmdEKYIjOP+vfk9yiXKcCDPwQPqBfF2SY2PyMfmZLt5pxwONz N+NxB6F8prkfRGj14jXWI84yQNgF+1IhBONTOdDWbkAaMmDE6EPXX5J9XqDKWwuo TF32jQ3CyWkimSOMVLx56MEfo+f8WjONCqiv5/odyi/51yD7nXNTYxeVzxJTq+3y aUPCDevaO4be7vKoDZxAOKw1Gyuz7GmFJ16SO/p2VaxMG9ZHhAeHfGitCVFkv+Al Yf7x0EFoWLD1VAgNn38iX+6rsWLAe+frUpJLRgF00OApTEaKipimwQ9FTveNIQM0 nyBmHZBw1hfs1zZahCSUaF/gv20Ewp6AC1xcJJMM2H0mjOiK6f57/rXMWSu2NBbb aBKDmJzLNNqdZE7ZsYdQ2YzhNiM4v5i4iMUBjU2MU3hTxcaA1NFm+4BBCD6P3/YP 56Pr5dojyQ+e2ISZH5am+SFu0ZJJoJOAScWjCIOZSYQgeAe4vHUl0mrvbhDjcodg v59mpSNAJibhOcZUBQTZBbKO0x32r8ZuKDUCyOFK56vhLP0TDTMXVXA4Kl7tAoQJ WQASZhPSJmM+7mqWNeIASWDbHDGBgDAjBgkqhkiG9w0BCRUxFgQUwGwiSqKiTkXW +IueoxiI4tONDrAwWQYJKoZIhvcNAQkUMUweSgBQAEsAQwBTADEAMgAgACgAcgBz AGEAKQAgAC0AawBlAHkAcABiAGUAIABQAEIARQAtAFMASABBADEALQBSAEMAMgAt ADEAMgA4MDEwITAJBgUrDgMCGgUABBSoNEHQ71kWU35Sgmprhdt+YWCrSQQIaDZt kZqPBPMCAggA -----END PKCS12----- -----BEGIN PKCS12----- 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 -----END PKCS12----- cryptostore-0.3.1.0/tests/files/rsa-public.pem0000644000000000000000000000101307346545000017442 0ustar0000000000000000-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0EbaQpZ9hPWNReZsOWuQPdZ/D SsoONN2ONKzAzYeCAy0RuK61z5zGehb4Np4/VLNJ1js1eVqq/N+0I8u/Mk1pEzge kb9cuoh25vmHOKxuvA3X9DvvOZS+vWRrs1pcpkO656k5Emw2HmUeSnbZVHQ7SlDf Ms2NfwhUAaR2mgTmIwIDAQAB -----END PUBLIC KEY----- -----BEGIN RSA PUBLIC KEY----- MIGJAoGBALQRtpCln2E9Y1F5mw5a5A91n8NKyg403Y40rMDNh4IDLRG4rrXPnMZ6 Fvg2nj9Us0nWOzV5Wqr837Qjy78yTWkTOB6Rv1y6iHbm+Yc4rG68Ddf0O+85lL69 ZGuzWlymQ7rnqTkSbDYeZR5KdtlUdDtKUN8yzY1/CFQBpHaaBOYjAgMBAAE= -----END RSA PUBLIC KEY----- cryptostore-0.3.1.0/tests/files/rsa-self-signed-cert.pem0000644000000000000000000000141207346545000021322 0ustar0000000000000000-----BEGIN CERTIFICATE----- MIICEDCCAXmgAwIBAgIJAPcN61ksKTebMA0GCSqGSIb3DQEBCwUAMCExHzAdBgkq hkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wHhcNMTgwNzAxMDkzNTE0WhcNMTgw NzMxMDkzNTE0WjAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMIGf MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0EbaQpZ9hPWNReZsOWuQPdZ/DSsoO NN2ONKzAzYeCAy0RuK61z5zGehb4Np4/VLNJ1js1eVqq/N+0I8u/Mk1pEzgekb9c uoh25vmHOKxuvA3X9DvvOZS+vWRrs1pcpkO656k5Emw2HmUeSnbZVHQ7SlDfMs2N fwhUAaR2mgTmIwIDAQABo1AwTjAdBgNVHQ4EFgQU/JTTK/+8Q86nWQwPMu+1PpT6 Bg4wHwYDVR0jBBgwFoAU/JTTK/+8Q86nWQwPMu+1PpT6Bg4wDAYDVR0TBAUwAwEB /zANBgkqhkiG9w0BAQsFAAOBgQCfbJlP9Y26k7fg/FV1ZTrlf2qYITgC1kottFrS JKSQRj3rWioOIxVaJo3Sw9V5XUag0LP0nyUspoSRHxvQXgqUnQrjhX7k/Qe9vVSc pXZKw3GSY1vHCM7xD71o2N3girECdLJDjnIw3grnHUI4kVdARMkCkVaEtnGADSGq ei1AZw== -----END CERTIFICATE----- cryptostore-0.3.1.0/tests/files/rsa-unencrypted-pkcs8.pem0000644000000000000000000000162407346545000021562 0ustar0000000000000000-----BEGIN PRIVATE KEY----- MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALQRtpCln2E9Y1F5 mw5a5A91n8NKyg403Y40rMDNh4IDLRG4rrXPnMZ6Fvg2nj9Us0nWOzV5Wqr837Qj y78yTWkTOB6Rv1y6iHbm+Yc4rG68Ddf0O+85lL69ZGuzWlymQ7rnqTkSbDYeZR5K dtlUdDtKUN8yzY1/CFQBpHaaBOYjAgMBAAECgYBDuQW4kRHIOJZJ5jpyw6xSRCK6 CD7F6QwKl7UBLktwklE5AQR0TIjh/Lj20VPi7bAgbPoHuoRnGoPn9C6E0h5abMag JUnhTwO6sKVBz27NYsNpsPVsaXgdomIHNDUFcfi/I19QEh4tua3EObnQM4007Tj2 auZutUnEJ4qQshJdgQJBAN+F5pV0dvNpkErxHBM8O8xM/Eu5IycWl756xskqJYrs XTCyLgLp3vNLFCInLm14MvRmWbVuErYXzamqElV7XPkCQQDOO4PjmAUCpNL0cOuN 9YIa3mRLtW0cqnLUtN2ZtqM3nFG0/KhVvQDsKpipdAp7qMWBj2rHGz8BL73AROu9 PC77AkATarFOGFDg8jGboPg8X4YeSC2+cjWwhpDl9gpgnS2ntMKfoUrH7AL3BXWZ RegNkFx0yJNQZGBxuv2dmG2BSXcZAkEAm0ke9wlphGMdYOeBxmN9MsQP2x3h6brC Oj1xuqNV5LK0p0WzbtOg1TMBvl5c4l3jUbnumbt/RmJvS03Z/6RIbwJBALgTXgcJ QzaiaD2r/XK7CCYHLVpjvNITHZFn+zcr8NdD1j4hWWIIIK/D3UJIymN+GuyG3h1P pvAPCqAcDl+WOTk= -----END PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/rsa-unencrypted-trad.pem0000644000000000000000000000156707346545000021472 0ustar0000000000000000-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQC0EbaQpZ9hPWNReZsOWuQPdZ/DSsoONN2ONKzAzYeCAy0RuK61 z5zGehb4Np4/VLNJ1js1eVqq/N+0I8u/Mk1pEzgekb9cuoh25vmHOKxuvA3X9Dvv OZS+vWRrs1pcpkO656k5Emw2HmUeSnbZVHQ7SlDfMs2NfwhUAaR2mgTmIwIDAQAB AoGAQ7kFuJERyDiWSeY6csOsUkQiugg+xekMCpe1AS5LcJJROQEEdEyI4fy49tFT 4u2wIGz6B7qEZxqD5/QuhNIeWmzGoCVJ4U8DurClQc9uzWLDabD1bGl4HaJiBzQ1 BXH4vyNfUBIeLbmtxDm50DONNO049mrmbrVJxCeKkLISXYECQQDfheaVdHbzaZBK 8RwTPDvMTPxLuSMnFpe+esbJKiWK7F0wsi4C6d7zSxQiJy5teDL0Zlm1bhK2F82p qhJVe1z5AkEAzjuD45gFAqTS9HDrjfWCGt5kS7VtHKpy1LTdmbajN5xRtPyoVb0A 7CqYqXQKe6jFgY9qxxs/AS+9wETrvTwu+wJAE2qxThhQ4PIxm6D4PF+GHkgtvnI1 sIaQ5fYKYJ0tp7TCn6FKx+wC9wV1mUXoDZBcdMiTUGRgcbr9nZhtgUl3GQJBAJtJ HvcJaYRjHWDngcZjfTLED9sd4em6wjo9cbqjVeSytKdFs27ToNUzAb5eXOJd41G5 7pm7f0Zib0tN2f+kSG8CQQC4E14HCUM2omg9q/1yuwgmBy1aY7zSEx2RZ/s3K/DX Q9Y+IVliCCCvw91CSMpjfhrsht4dT6bwDwqgHA5fljk5 -----END RSA PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/x25519-encrypted-pbes1.pem0000644000000000000000000000302007346545000021261 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MFcwGwYJKoZIhvcNAQUDMA4ECOlAaqWwdDweAgIIAAQ42XsuUzVmkZkOq+m4uBNW 6qzsaTJ7FPa4itB+tyv4BzPgFxAQTwzzJgSr9WkbYy6LKZIPporO/Ko= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MFcwGwYJKoZIhvcNAQUKMA4ECH0TpXboY9MNAgIIAAQ4dojWsXYBrtraqLi1pBeF uOyGGClKoj7XpGvXkNShtEnWTKjlNUebf02xQlcmxuksdXNffTMdsww= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MFAwHAYKKoZIhvcNAQwBATAOBAjV52wnNhxkeAICCAAEMN5Tklnapb+agqTYnDle pHKk61c0d0la81SFGz5pqFBPllX5zmnSWzzHFW7/B8cxLw== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MFAwHAYKKoZIhvcNAQwBAjAOBAh7Iwy1tOrlZAICCAAEMK0FLzIhsz8+1ox7grnf +u+eD8k9LJ0X77X9GeNKyvIJl5lkkWaCblFwd2reMH3eug== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MFgwHAYKKoZIhvcNAQwBAzAOBAgWrZKj/deGGQICCAAEOJOPMtVYLKsvzajTT5wG hjhbX7RHWL9t9h1H1m/CAW/qJqALZNPQcQ8BiheRJv8LrgYr+Fzl4e6O -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MFgwHAYKKoZIhvcNAQwBBDAOBAjPUjiYWb4CwwICCAAEOASPWNTFFZaViFQ+WQ4C Upl6k5aTHq6KHpai/N6ABiwV8dcXAL5CXMzAxJWKW+ZdUgyydM7xAVn6 -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MFgwHAYKKoZIhvcNAQwBBTAOBAgbZrk3W2y+WgICCAAEONIxa0JMYEvV9curAwn5 5epAnnwv7vtqO/IT4mqkc0WLHPEZVhxL2EQWBGemGQWPxeRV5jK8RJvS -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MFgwHAYKKoZIhvcNAQwBBjAOBAgfr3469Ve4gAICCAAEOMHa3S4OYcEBCb+HHvJW zpNlWtmW4/djMndGWpznIuguxK/7V+A3R7PgvA8K0FhpSPDR3bs/2QHW -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/x25519-encrypted-pbkdf2.pem0000644000000000000000000000360307346545000021426 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIGHMEsGCSqGSIb3DQEFDTA+MCkGCSqGSIb3DQEFDDAcBAj6ZyFipSgetQICCAAw DAYIKoZIhvcNAgkFADARBgUrDgMCBwQIjgzX3kQ5dXgEOKlxrj9EtG1DNXBDgzDW vnFReEN4zACwoxMQ41sAASIW1vCT1TuTIDXLxGM5CwfkyawnexrKlKmt -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGKME4GCSqGSIb3DQEFDTBBMCkGCSqGSIb3DQEFDDAcBAj4aVxRNkgd/QICCAAw DAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQIu/UnAKsbyacEOE3fiHQdWKYI5Inf Wndw5d7UX0nRmCjwNQLK1UL+QXujoVmi+3hEZSRfYcqj5M4t7sJlzZ63w8Td -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGLME8GCSqGSIb3DQEFDTBCMCkGCSqGSIb3DQEFDDAcBAgJmEUBljH9VAICCAAw DAYIKoZIhvcNAgkFADAVBgkqhkiG9n0HQgoECB9jZKjkRqv6BDg7458AElgxBUGx 9iPo02FNkzdUO23NB66AV0puFZAYz4NUY/wgJLA3HMwBERdSP74hBjh+GUT3sw== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGdMFkGCSqGSIb3DQEFDTBMMCkGCSqGSIb3DQEFDDAcBAjyCgD/RmiEIgICCAAw DAYIKoZIhvcNAgkFADAfBgsqgwiMmks9AQEBAgQQFNpqaqXLMkVwoDSdtl+SEwRA XXRprNwSjtJ/m6V3vFKq+VCHOrj7o2MSpt/pvjVnbHKaHgX9V3TP8e1KOiiXJoo1 PBv4M1beoCokVjhCECZWyg== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGSMFYGCSqGSIb3DQEFDTBJMCwGCSqGSIb3DQEFDDAfBAiTO27y8UQ3LwICCAAC ARAwDAYIKoZIhvcNAgkFADAZBggqhkiG9w0DAjANAgE6BAibXxpEYv15IAQ4zEoc lFpScRoeJ/6aaSI6f4NFG4N4cVFTXvi5YIDlbpwmz4xdIr2uU+jhiGknXDcE2Z+m ERCITjQ= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGTMFcGCSqGSIb3DQEFDTBKMCwGCSqGSIb3DQEFDDAfBAgxud22g8Bm+AICCAAC AQUwDAYIKoZIhvcNAgkFADAaBggqhkiG9w0DAjAOAgIAoAQISGwHgT4bmFkEOC8m drQbC9WA1ZvACMJWLXEL4JUgejLRDtfcvCC5kAhT2iy23RllpUftspZ4V/SzAePa EFsn0jy8 -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGSMFYGCSqGSIb3DQEFDTBJMCwGCSqGSIb3DQEFDDAfBAiQqqDVfFc5OwICCAAC AQgwDAYIKoZIhvcNAgkFADAZBggqhkiG9w0DAjANAgF4BAgmnqFFlLCrwAQ4elCp HTXrBbgtWoMW/hG5AUn2Vc9W3ycJ9tw9d4pxx3ZHV+FGiEMJsxqPwGVEDJvTgxy8 G55j3UE= -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/x25519-encrypted-scrypt.pem0000644000000000000000000000150207346545000021576 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIGTME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAjTIFxP0Hwq3wICQAAC AQgCAQEwHQYJYIZIAWUDBAECBBDJmyEj4MkNJQMLM4t25IIuBECqSAJnq6gSp0Nc OwqkgspkwyYGxHfZAJ/aw7BHSGTs+LQexB738lqY/B5Ri2udxqfE/kjKzyn2KTHJ nqHQk8+J -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGTME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAi0kO+7kfp0NwICQAAC AQgCAQEwHQYJYIZIAWUDBAEWBBBnSlCJdiXvxblUH3GgOP3iBECaLsAsyLbHLKcA JCxrNQ3JrGL0TVQHPu/6tYFAWJoM4ZCIww1i5nXZUIigNDYERUJbm9od6E2a8apA TH5JE4yf -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGTME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAjC70jTpl9lAQICQAAC AQgCAQEwHQYJYIZIAWUDBAEqBBCKvOsxUwHu7QYwy/j409InBECFy0tXOpJYZD1V S+x0XsC/nHHesRzKKbs86f//VcOQBOwbA044IcUNPiaSkuedtlAX84I1rtvtJGY6 b7fVHtJn -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/x25519-public.pem0000644000000000000000000000016107346545000017535 0ustar0000000000000000-----BEGIN PUBLIC KEY----- MCowBQYDK2VuAyEAdNNs0T64alqPXbwrJt+rCdkerW6PgrQOUKHUlbPyahA= -----END PUBLIC KEY----- cryptostore-0.3.1.0/tests/files/x25519-self-signed-cert.pem0000644000000000000000000000074507346545000021422 0ustar0000000000000000-----BEGIN CERTIFICATE----- MIIBOjCBpAIBATANBgkqhkiG9w0BAQsFADAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0 QGV4YW1wbGUuY29tMB4XDTE4MDkwMjE1NTA1M1oXDTE4MTAwMjE1NTA1M1owITEf MB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTAqMAUGAytlbgMhAHTTbNE+ uGpaj128KybfqwnZHq1uj4K0DlCh1JWz8moQMA0GCSqGSIb3DQEBCwUAA4GBAE5F wEzoWRJKgS6OYunevbkvDMOmAjhXg+P2zcuXSndAi6HLlHTsx0tdiTclrNqNkFcw XaSBmGhpWy/qI4eM/lrWZV3+dfeNRBb6oqezjgbepC+J1akDNzseW1+Kr16ryQz9 STwnOqpQhrTQdBOaLlgofw3qqj88bWBsNciJWCX4 -----END CERTIFICATE----- cryptostore-0.3.1.0/tests/files/x25519-unencrypted-pkcs8.pem0000644000000000000000000000016707346545000021653 0ustar0000000000000000-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VuBCIEIIhgx84XP3vLVdFwZWT88BG/gGRXl6YYUeo0lWX2E8RY -----END PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/x448-encrypted-pbes1.pem0000644000000000000000000000343007346545000021120 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MG8wGwYJKoZIhvcNAQUDMA4ECB4xXEg3WSinAgIIAARQM2CTxuxMnzkPDjXsonc3 lI7dqFNYNxBfgGoEur60JvnZyl7atO+lsCY08XYqLOAVwf/5aZC9Crkd0iHdtYZs k8xCAG/KXBwdrrMiKgoRdXE= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MG8wGwYJKoZIhvcNAQUKMA4ECJFkCK4Fg7SgAgIIAARQ8CiLyhuksya2/pWvoemD etLFhTSKFln9XfLXSyG70yCsPcH8kC5Xv3ppmNcgbYDC8iwxWwjH4b0QM/QuzaGK F3itJG5sgWypa9Yt2rSwYUk= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MGgwHAYKKoZIhvcNAQwBATAOBAi75GJorMne3AICCAAESLScu+UVIvP1/FqkKBa1 lYTe0Z1nQWFs5bFdFsAAvw5RCSee2vcgFA5KhIqlPwdPgxmgAzIYgoSV0RqudMfq OpABx2fMhpMhfA== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MGgwHAYKKoZIhvcNAQwBAjAOBAjxiQQdgW2rXwICCAAESHEAGY2q5vNhLbN7Swb1 UmDvXibgMjhTpunsmPouCahSf6Zvv8ahes53gvPg/j14hplD2d/MRDz5VRxYO7dP v2mzZzuqhegssw== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MHAwHAYKKoZIhvcNAQwBAzAOBAhQmGA2NmFbsQICCAAEUAxfvgmmGrViSF3kj82o EbNw0fbLqoaa/SdNfV6KRJhZ8j/+6URQ0xKMw3sSCp/fwSon8h9I633VkGyxEtyF KRYOakvY5kBOt+JYiZcbovFT -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MHAwHAYKKoZIhvcNAQwBBDAOBAhziSywPrS4zQICCAAEUJaEyqSGPu9FZ9CLURVW 6ZRWj6TIaehX0cGGFCkTk3JqhpFFRNLte0SLGPkankzXKOV3D5mBUPF+UjvXSwaJ FcyeszvN5xR6sNQkETZqpTD3 -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MHAwHAYKKoZIhvcNAQwBBTAOBAj1Ch4rgGz1ywICCAAEUDJ1FbgIb/MHcuoLexYq dqMB7sGctwBmrFZRTpbbHGNvEUV6MFlBkximrCb9nnHjCKj2sZcfQp0R5Q1YODn8 gzEAEjVuh2yFCKlwumPknt+O -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MHAwHAYKKoZIhvcNAQwBBjAOBAhCm0/fGye6+gICCAAEUHqw28mTyCaI6k+ILt/o 3qleloo0f4bL9cJiOBYnUB/S1AElr/85ULA70bECsjsWjoWsRE8IxJ5a3FtWJaat gaNyLYQlMtVBMoK6feFFT8aE -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/x448-encrypted-pbkdf2.pem0000644000000000000000000000413207346545000021256 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIGfMEsGCSqGSIb3DQEFDTA+MCkGCSqGSIb3DQEFDDAcBAgJDIKD8sQsoQICCAAw DAYIKoZIhvcNAgkFADARBgUrDgMCBwQIuYP9T2Y/nD4EUBXfNNfUENf19FHDdt9Z b3s0OVeXeMbu+80TA2mtbk+wOucvB69hr8V/ZFW2HDiYJ2qMBMioOw197lTtVMIT xS6gGSpl+tyPoWIoycGcnsq6 -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGiME4GCSqGSIb3DQEFDTBBMCkGCSqGSIb3DQEFDDAcBAgu+SJlXxKQDAICCAAw DAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQIeyJz7DTK2+QEUIlmFpQp5DB+gwVp 6G6dhe10uhETbfSTN8+lmYiqb+0p91DnV+3kpaTrT6fuU3hsjTH1xx4a2oElc+T1 m8xZhvmmyued7UPBrQdy2RcNUToQ -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGjME8GCSqGSIb3DQEFDTBCMCkGCSqGSIb3DQEFDDAcBAiHVuSXubRGxwICCAAw DAYIKoZIhvcNAgkFADAVBgkqhkiG9n0HQgoECJoupjD8iD9gBFAIaJQUeSI3WfZn vJ5oM88JZrDdxVKlZlOL4ffXYu3PIUSlV0r3V08m/sPMY/7hCmtvyxBkw6ncB9su +0tC+fIu1+VVotbarL2eaZaxC217ew== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGtMFkGCSqGSIb3DQEFDTBMMCkGCSqGSIb3DQEFDDAcBAjkfqkzdtzUKQICCAAw DAYIKoZIhvcNAgkFADAfBgsqgwiMmks9AQEBAgQQG/iQQd82wsC5mQN+bFY58ARQ 1QsQhP+TfWeZP9oztCd7s0Y1PnTM7WsMW2YtyS6Sn1Duyj9gx17cXLWvzQz9mS1Y EoORulT1bTOzj585xSrNQLSqlnqTHcczNPKHCpU7EWE= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGqMFYGCSqGSIb3DQEFDTBJMCwGCSqGSIb3DQEFDDAfBAg5ABTk7x6EhgICCAAC ARAwDAYIKoZIhvcNAgkFADAZBggqhkiG9w0DAjANAgE6BAiwam2gNHnwhgRQdpEG +fxlriH5rAAFneldLBFHSjBMSKJZNftQv0HFOQzwPhoiYKGXrcldx4bq4B1cbSJR XFNvROPF/F3g0B/xn3YiU/5weo5B6Rsu1ojqTBA= -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGrMFcGCSqGSIb3DQEFDTBKMCwGCSqGSIb3DQEFDDAfBAiWX47sRP/MnQICCAAC AQUwDAYIKoZIhvcNAgkFADAaBggqhkiG9w0DAjAOAgIAoAQIsvG8iVYWSzMEUBmO u0pBmQkmBM3VI8A9cCRob5hAUojyd4NpodMJvpY4Da7mz20LgLyL5q2DsKgTfnzn VTf+tP8vTv8i76Pr7aU89P784jI8nbtZgkcYizq+ -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGqMFYGCSqGSIb3DQEFDTBJMCwGCSqGSIb3DQEFDDAfBAhkgv+PZmmr5gICCAAC AQgwDAYIKoZIhvcNAgkFADAZBggqhkiG9w0DAjANAgF4BAjKasCGhxd/5ARQa6xv vi/LtSLtwvrYHgWVGELLgkwqBJ6d2MM+ysEUeQILq5gbGcdnfGHtrakVtFir2ga6 lyrpv9Y0m5gLqgU0QPbm9XRqu1hdEKanozFs2H4= -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/x448-encrypted-scrypt.pem0000644000000000000000000000161207346545000021432 0ustar0000000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIGjME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAiW/EHVo6GeIQICQAAC AQgCAQEwHQYJYIZIAWUDBAECBBAmafVnJcoBMlXmITIT+/hxBFCP8hh1dr4EGyMt yqivyYBBAlCfjbAquHwPcys7kELHgwHG0PAgspAKkOLCqSgZVuomuS1Ya6bNzgeI S2iW5nYwXL8QjIYYEXAxLx8ZQMVb0A== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGjME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAhixLMqBNK2tAICQAAC AQgCAQEwHQYJYIZIAWUDBAEWBBAA5uc3FQno7xKz2V8kxSCeBFACaBwzab3adlDg bAIOfR1ytgNEI8+jLDxcPtEI6TjtmcLsT6NI3MaQfOnLy/gt/Uo5XbbiMJUGZ4Mm ggEjLTPc7M2kLgGdKcLpnc8mWBCgyg== -----END ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY----- MIGjME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAhULg3jQtrIRwICQAAC AQgCAQEwHQYJYIZIAWUDBAEqBBBk6w5yfaTk8et4FwnFTrfRBFBl+mFvAdi6X6Wm 44LkvMjiVCZ1xGDwLcZOyc5OnyNOHnW5tLBa7qvghaQljOyHS+na0z9uKTalbvRP GaYKE3JRIsi9MzXOSXlZHLl6fDiVRw== -----END ENCRYPTED PRIVATE KEY----- cryptostore-0.3.1.0/tests/files/x448-public.pem0000644000000000000000000000022207346545000017365 0ustar0000000000000000-----BEGIN PUBLIC KEY----- MEIwBQYDK2VvAzkA3cHetiJ/T/5Oo62IF1sDHfTBN9TUjxcTMhX3lHxw8W5ryxQ8 LWc2VD0RcfBn1BI3+QVEefPUd/c= -----END PUBLIC KEY----- cryptostore-0.3.1.0/tests/files/x448-self-signed-cert.pem0000644000000000000000000000100607346545000021243 0ustar0000000000000000-----BEGIN CERTIFICATE----- MIIBUjCBvAIBATANBgkqhkiG9w0BAQsFADAhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0 QGV4YW1wbGUuY29tMB4XDTE4MDkwMjE1NTA1M1oXDTE4MTAwMjE1NTA1M1owITEf MB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTBCMAUGAytlbwM5AN3B3rYi f0/+TqOtiBdbAx30wTfU1I8XEzIV95R8cPFua8sUPC1nNlQ9EXHwZ9QSN/kFRHnz 1Hf3MA0GCSqGSIb3DQEBCwUAA4GBACwDI7X1kRJwPjDXTB1lkmf0U806ng0NuFuY mXgt+PYiUhR3g76FC0chw2+WeeQ6WE4VkQsfdZz10bSWGtcaH4fCYVkQXF/BmNz8 7Mv0L9iK2438SBcK3WAYB+bC9CZw/gKObzDHxml4tlDaMmIsfYVqiHXuEAPI3wjw qoHmxWqY -----END CERTIFICATE----- cryptostore-0.3.1.0/tests/files/x448-unencrypted-pkcs8.pem0000644000000000000000000000023007346545000021474 0ustar0000000000000000-----BEGIN PRIVATE KEY----- MEYCAQAwBQYDK2VvBDoEOOC8GlnbqcOSJ+ISHV8HJTD3WGdC1sQdZ+0Gkx7sUvL0 Bm0KxY3cO9Rg9MQb3qkfVngRes0sb86Q -----END PRIVATE KEY-----