Types
AtomicPasswordHandler = object of PasswordHandler
Cert = object public*: PublicKey private*: PrivateKey primaryKeyId*: string subkeys*: Table[string, Subkey]
CertGenerationFailedException = object of SequoiaException
CertHasEncryptedKeyException = object of SequoiaException
CertLacksPrivateKey = object of NimSideSequoiaException
CertMaybeRevokedException = object of SequoiaException
CertParsingException = object of SequoiaException
CertRevokedException = object of SequoiaException
Decryption = object successful*: bool body*: string
ExpectedPrivateKeyGotPublicException = object of MissMatchingKey
FailedToEncryptKeyException = object of SequoiaException
FailedToParseKeyException = object of CertParsingException
FailedToParseKeyPrivateException = object of CertParsingException
FailedToParseKeyPublicException = object of CertParsingException
FailedToParseMessageException = object of SequoiaException
FailedToReadFromBufferException = object of SequoiaException
FailedToRevokePrimaryKeyException = object of SequoiaException
FailedToRevokeSubkeyException = object of SequoiaException
FailedToWriteMessageException = object of SequoiaException
GlobalPasswordHandler = object of PasswordHandler
IncorrectKeyFlagsException = object of MissMatchingKey
MissMatchingKey = object of SequoiaException
NimSideSequoiaException = object of SequoiaException
NoKeyMeetsSelectionException = object of SequoiaException
PackedParserFailedToRecurseException = object of SequoiaException
PasswordException = object of SequoiaException
PasswordHandler = object of RootObj
PrivateKey = string
PublicKey = string
SequoiaException = object of CatchableError
Subkey = object keyFlags*: set[KeyTypes] keyId*: string expires*: bool validLengthSeconds*: uint64 creationTime*: uint64
UninitiatedSubkey = object cipher*: CryptSuites = Cv25519 keyFlags*: set[KeyTypes] keyId*: string expires*: bool validLengthSeconds*: uint64
Verification = object isValid*: bool body*: string
Procs
proc convertGlobalPasswordToAtomic(a: Cert; b: GlobalPasswordHandler): AtomicPasswordHandler {. ...raises: [], tags: [], forbids: [].}
-
This is usually used in the context of creating a keyring with newPasswordHandlerKeyring... This design allows you to both have simple to make global keys, and make them work in key rights simply. Its needed because otherwise the handler has no way of knowing what keys map to what.
Example:
import sequtils import sugar import nimPGP let signingKey = newSubkey({ForSigning}) let transportKey = newSubkey({ForTransport}) let certOne = newCert(@[signingKey, transportKey]) let certTwo = newCert(@[signingKey, transportKey]) #Creates a handler that can be now used with [newPasswordHandlerKeyring] let handlerOne = convertGlobalPasswordToAtomic(certOne, newPasswordHandler("hellofutureme")) let handlerTwo = convertGlobalPasswordToAtomic(certTwo, newPasswordHandler("hellopastme")) let encryptedCertOne = encryptKeys(certOne, handlerOne) let encryptedCertTwo = encryptKeys(certTwo, handlerTwo) let encryptedMessage = sendMessage(encryptedCertTwo.public, "hello!") let keyring = newPasswordHandlerKeyring(handlerOne, handlerTwo) let keys = @[encryptedCertOne, encryptedCertTwo].map(x => x.private) let unencryptedMessage = decryptMessage(keys, encryptedMessage, keyring) doAssert unencryptedMessage.body == "hello!"
proc decryptMessage(privateKeys: openArray[PrivateKey] or PrivateKey or seq[PrivateKey]; message: string; passwordHandler = AtomicPasswordHandler()): Decryption
-
For the inverse procedure, see sendMessage
Can take in multiple private keys, but you must create a password keyring using newPasswordHandlerKeyring
Capable of raising the following exceptions:
FailedToParseKeyPrivateException, CertRevokedException, NoKeyMeetsSelectionException
ExpectedPrivateKeyGotPublicException, CertIsInvalidException
FailedToParseMessageException, FailedToReadFromBufferException, PackedParserFailedToRecurseException
IncorrectPasswordForSecretKeyException, FoundEncryptedSecretButNoPasswordHandlerException, PasswordSetToAtomicButMissingEncryptedKeyidException
Example:
import nimPGP let cert = newCert(@[newSubkey({ForTransport}), newSubkey({ForSigning})]) let signedMessage = signMessage(cert.private, "Confidential Information") let encrypted = sendMessage(cert.public, signedMessage) let decrypted = decryptMessage(cert.private, encrypted) doAssert decrypted.successful echo verifySignature(cert.public, decrypted.body)
With KeyringExample:
import nimPGP import sequtils import sugar let pwArray = [newPasswordHandler("two"), newPasswordHandler("one"), newPasswordHandler("three")] let subkey = newSubkey({ForTransport}) let certs = collect(for x in 0 .. 2: encryptKeys(newCert(@[subkey]), pwArray[x])) # They **need** to be atomic handlers in order to know which keys # are used for let atomicPws = collect(for x in 0 .. 2: convertGlobalPasswordToAtomic(certs[x], pwArray[x])) let messages = [certs[0].public.sendMessage("0"), certs[1].public.sendMessage("1"), certs[2].public.sendMessage("2")] let macroHandler = newPasswordHandlerKeyring(atomicPws) for x in 0 .. messages.high: let decrypted = decryptMessage(certs.map(x=>x.private), messages[x], macroHandler) doASsert decrypted.successful == true
proc encryptKeys(a: Cert; newPassword: PasswordHandler; oldPassword = PasswordHandler()): Cert {....raises: [ FailedToWriteMessageException, ExpectedPrivateKeyGotPublicException, FailedToParseKeyPublicException, FailedToParseKeyPrivateException, NoKeyMeetsSelectionException, FailedToParseMessageException, PackedParserFailedToRecurseException, FailedToReadFromBufferException, CertGenerationFailedException, FailedToParseKeyException, CertRevokedException, FailedToRevokeSubkeyException, FailedToRevokePrimaryKeyException, FailedToEncryptKeyException, CertMaybeRevokedException, FoundEncryptedSecretButNoPasswordHandlerException, PasswordSetToAtomicButMissingEncryptedKeyidException, IncorrectPasswordForSecretKeyException, IncorrectKeyFlagsException, CertIsInvalidException, KeyError], tags: [], forbids: [].}
-
Applies the newPassword specifications to the given cert.
Allows for re-encryption of a key with oldPassword, which corresponds ot the current decryption method.
Capable of raising the following exceptions:
FailedToParseKeyPrivateException, ExpectedPrivateKeyGotPublicException, NoKeyMeetsSelectionException
FailedToEncryptKeyException, FailedToWriteMessageException, CertIsInvalidException
Example:
import nimPGP let signingKey = newSubkey({ForSigning}) let transportKey = newSubkey({ForTransport}) let unencryptedCert = newCert(@[signingKey]) let pwHandler = newPasswordHandler("password12345!") let certEncrypted =encryptKeys(unencryptedCert, pwHandler)
proc getRecipients(message: string): seq[string] {....raises: [ FailedToWriteMessageException, ExpectedPrivateKeyGotPublicException, FailedToParseKeyPublicException, FailedToParseKeyPrivateException, NoKeyMeetsSelectionException, FailedToParseMessageException, PackedParserFailedToRecurseException, FailedToReadFromBufferException, CertGenerationFailedException, FailedToParseKeyException, CertRevokedException, FailedToRevokeSubkeyException, FailedToRevokePrimaryKeyException, FailedToEncryptKeyException, CertMaybeRevokedException, FoundEncryptedSecretButNoPasswordHandlerException, PasswordSetToAtomicButMissingEncryptedKeyidException, IncorrectPasswordForSecretKeyException, IncorrectKeyFlagsException, CertIsInvalidException], tags: [], forbids: [].}
-
Gets the keyids for which a pgp message is encrypted for.
Capable of raising the following exceptions:
FailedToParseMessageException, PackedParserFailedToRecurseException, CertIsInvalidException
Example:
import nimPGP import sequtils import sugar import tables let certOne = newCert(@[newSubkey({ForTransport})]) let certTwo = newCert(@[newSubkey({ForTransport})]) let message = sendMessage(certOne.private, "for your eyes only!") let recipients = getRecipients message echo recipients.any(x => x in certOne.subkeys) echo recipients.any(x => x in certTwo.subkeys)
proc isPrimaryKeyRevoked(key: PublicKey): RevocationStatus {....raises: [ FailedToWriteMessageException, ExpectedPrivateKeyGotPublicException, FailedToParseKeyPublicException, FailedToParseKeyPrivateException, NoKeyMeetsSelectionException, FailedToParseMessageException, PackedParserFailedToRecurseException, FailedToReadFromBufferException, CertGenerationFailedException, FailedToParseKeyException, CertRevokedException, FailedToRevokeSubkeyException, FailedToRevokePrimaryKeyException, FailedToEncryptKeyException, CertMaybeRevokedException, FoundEncryptedSecretButNoPasswordHandlerException, PasswordSetToAtomicButMissingEncryptedKeyidException, IncorrectPasswordForSecretKeyException, IncorrectKeyFlagsException, CertIsInvalidException], tags: [], forbids: [].}
- To revoke a primary key, see RevokePrimaryKey
proc isSubkeyRevoked(key: PublicKey; keyid: string or Subkey): RevocationStatus
- To revoke a subkey, see RevokeSubkey
proc newCert(subkeySeq: seq[UninitiatedSubkey] | openArray[UninitiatedSubkey]; primaryCipher: CryptSuites = Cv25519; user_ids: seq[string] = @[]; validLength: uint32 | Duration = uint32 0): Cert
-
Generates a new PGP Cert.
A given Cert can have a maximum of 256 unique subkeys, this applies to both scaffoldKey and this procedure. This can be boosted if people have issues.
validLength takes in either a uint32 in seconds or a duration.
It is the length of time until it expires, e.g validLength = 60*60*24*365 = ~1 year until expiry. If it was made on 1/1/2050 it would expire on 1/1/2051
If Duration > 2^32 (4294967295, uint32.high, ~136.192 years) then a OverflowDefect is raised. This is because duration on the Rust side uses SystemTime, which has a maximum of u32 when accepting from seconds
The minimum length until it is invalid duration is 100 seconds.
Note: Due to Sequoia's security limitations, you CANNOT make a key which both signs and encrypts data This would raise a KeyCannotBeUsedForTransportAndSigningException inherited from CertGenerationFailedException
Also note: Keys Generated with new cert are not encrypted. To encrypt them see encryptKeys
There is a maximum of 254 subkeys per key
Capable of raising: CertGenerationFailedException, FailedToWriteMessageException
Example:
import nimPGP let signingKey = newSubkey({ForSigning}) let transportKey = newSubkey({ForTransport}) let cert = newCert(@[signingKey, transportKey]) let signedMessage = signMessage(cert.private, "Hello, World!") let verification = verifySignature(cert.public, signedMessage) doAssert verification.isValid == true doAssert verification.body == "Hello, World!"
proc newPasswordHandler(globalPassword: string): GlobalPasswordHandler {. ...raises: [], tags: [], forbids: [].}
-
Creates a password handler where, one password is used for all keys.
There is an overload function which takes in a Table[string, string] for atomic password handling.
This also encrypts the primary key.
A GlobalPasswordHandler cannot be used in newPasswordHandlerKeyring and needs to be converted into an AtomicPasswordHandler using convertGlobalPasswordToAtomic.
Example:
import nimPGP let signingKey = newSubkey({ForSigning}) let transportKey = newSubkey({ForTransport}) let certUnencrypted = newCert(@[signingKey, transportKey]) let pwHandler = newPasswordHandler("A really super duper good password!") let certEncrypted = encryptKeys(certUnencrypted, pwHandler)
proc newPasswordHandler(keyidToPassword: Table[string, string]): AtomicPasswordHandler {. ...raises: [], tags: [], forbids: [].}
-
Creates a password handler where, each keyid provided has a unique password.
Not all keyids are required to be in the table, they will not be encrypted.
Example:
import nimPGP import sequtils import tables let signingKey = newSubkey({ForSigning}) let transportKey = newSubkey({ForTransport}) let unencryptedCert = newCert(@[signingKey, transportKey]) let keys = unencryptedCert.primaryKeyId & unencryptedCert.subkeys.keys.toSeq() let pwHandler = newPasswordHandler({keys[0] : "a", keys[1] : "b", keys[2] : "c"}.toTable()) let certEncrypted = encryptKeys(unencryptedCert, pwHandler)
proc newPasswordHandlerKeyring(handlers: varargs[AtomicPasswordHandler]): AtomicPasswordHandler {. ...raises: [], tags: [], forbids: [].}
proc newSubkey(keyFlags: set[KeyTypes]; cipher: CryptSuites = Cv25519; validLength: uint32 or Duration = uint32 0): UninitiatedSubkey
-
Creates a new UninitiatedSubkey which can be turned into a subkey in NewCert
Note: While you can put arbitrary ciphers for a given key, the ciphers are unknowable due to Sequoia side reasons.
Thus, I recommend you not use whacky combinations of ciphers, unless you want reconstruct your ciphers using the flags and validLength, which i do not recommend as this is a a very recognizable fingerprint.
ValidLength is in seconds, see newCert for more detail
proc revokePrimaryKey(cert: Cert; reason: ReasonForRevocation = Unspecified; message: string = ""; passwordHandler = PasswordHandler()): Cert {....raises: [ CertLacksPrivateKey, FailedToWriteMessageException, ExpectedPrivateKeyGotPublicException, FailedToParseKeyPublicException, FailedToParseKeyPrivateException, NoKeyMeetsSelectionException, FailedToParseMessageException, PackedParserFailedToRecurseException, FailedToReadFromBufferException, CertGenerationFailedException, FailedToParseKeyException, CertRevokedException, FailedToRevokeSubkeyException, FailedToRevokePrimaryKeyException, FailedToEncryptKeyException, CertMaybeRevokedException, FoundEncryptedSecretButNoPasswordHandlerException, PasswordSetToAtomicButMissingEncryptedKeyidException, IncorrectPasswordForSecretKeyException, IncorrectKeyFlagsException, CertIsInvalidException], tags: [], forbids: [].}
-
To check if a primary key is revoked, see isPrimaryKeyRevoked
Capable of raising the following exceptions:
FailedToParseKeyPrivateException, ExpectedPrivateKeyGotPublicException, NoKeyMeetsSelectionException
FailedToRevokePrimaryKeyException, FailedToWriteMessageException, CertIsInvalidException
IncorrectPasswordForSecretKeyException, FoundEncryptedSecretButNoPasswordHandlerException, PasswordSetToAtomicButMissingEncryptedKeyidException
Example:
import nimPGP let cert = newCert(@[newSubkey({ForSigning})]) let revokedCert = revokePrimaryKey(cert, reason = KeyRetired, "I got bored of this key") echo isPrimaryKeyRevoked(revokedCert.public)
proc revokeSubkey(cert: Cert; subkey_keyid: string; reason: ReasonForRevocation = Unspecified; message: string = ""; passwordHandler = PasswordHandler()): Cert {....raises: [ CertLacksPrivateKey, FailedToWriteMessageException, ExpectedPrivateKeyGotPublicException, FailedToParseKeyPublicException, FailedToParseKeyPrivateException, NoKeyMeetsSelectionException, FailedToParseMessageException, PackedParserFailedToRecurseException, FailedToReadFromBufferException, CertGenerationFailedException, FailedToParseKeyException, CertRevokedException, FailedToRevokeSubkeyException, FailedToRevokePrimaryKeyException, FailedToEncryptKeyException, CertMaybeRevokedException, FoundEncryptedSecretButNoPasswordHandlerException, PasswordSetToAtomicButMissingEncryptedKeyidException, IncorrectPasswordForSecretKeyException, IncorrectKeyFlagsException, CertIsInvalidException], tags: [], forbids: [].}
-
To check if a subkey is revoked, see isSubkeyRevoked
Capable of raising the following exceptions:
FailedToParseKeyPrivateException, ExpectedPrivateKeyGotPublicException, NoKeyMeetsSelectionException
FailedToRevokeSubkeyException, FailedToWriteMessageException, CertIsInvalidException
IncorrectPasswordForSecretKeyException, FoundEncryptedSecretButNoPasswordHandlerException, PasswordSetToAtomicButMissingEncryptedKeyidException
Example:
import nimPGP import tables import sequtils let cert = newCert(@[newSubkey({ForSigning})]) # returns a new Cert, does not mutate the previous one let subkey = cert.subkeys.keys.toSeq()[0] let revokedCert = revokeSubkey(cert, subkey, reason = KeyRetired, "I got bored of this key") echo isSubkeyRevoked(revokedCert.public, subkey)
proc scaffoldKey(key: PublicKey or PrivateKey): Cert
-
Takes in a private or public key, and parses the keys. If a public key is provided, there will be no private key field.
Capable of raising the following exceptions:
FailedToParseKeyException, FailedToWriteMessageException, CertIsInvalidException
Example:
import nimPGP import tables import sequtils import json let privateKey = parseJson(readFile("./src/tests/foregin_certs.json"))[0]["private"].getStr() #-----BEGIN PGP PRIVATE KEY BLOCK-----\n[data]----END PGP PRIVATE KEY BLOCK----- echo scaffoldKey(privateKey)
proc sendMessage(publicKeys: openArray[PublicKey] or PublicKey or seq[PublicKey]; message: string): string
-
For the inverse procedure, see DecryptMessage
Can take in a OpenArray or Seq if you wish to send to multiple public keys
Capable of raising the following exceptions:
FailedToParseKeyPublicException, CertRevokedException, NoKeyMeetsSelectionException
FailedToWriteMessageException, CertIsInvalidException
Example:
import nimPGP let cert = newCert(@[newSubkey({ForTransport}), newSubkey({ForSigning})]) let signedMessage = signMessage(cert.private, "Confidential Information") echo sendMessage(cert.public, signedMessage)
proc signMessage(privateKey: PrivateKey; message: string; keyid: string or Subkey = ""; passwordHandler = PasswordHandler()): string
-
For the verification procedure, see verifySignature
Capable of raising the following exceptions:
FailedToParseKeyPrivateException, ExpectedPrivateKeyGotPublicException, CertRevokedException,
FailedToWriteMessageException, NoKeyMeetsSelectionException, IncorrectKeyFlagsException, CertIsInvalidException
IncorrectPasswordForSecretKeyException, FoundEncryptedSecretButNoPasswordHandlerException, PasswordSetToAtomicButMissingEncryptedKeyidException
Example:
import nimPGP let cert = newCert(@[newSubkey({ForSigning})]) doAssert (verifySignature(cert.public,signMessage(cert.private, "Hello!"))).isValid == true
proc verifySignature(publicKeys: openArray[PublicKey] or PublicKey or seq[string]; message: string): Verification
-
For signing of text, see signMessage
Capable of raising the following exceptions:
FailedToParseKeyPublicException, CertRevokedException, NoKeyMeetsSelectionException
FailedToParseMessageException, FailedToReadFromBufferException, PackedParserFailedToRecurseException
Example:
import nimPGP let cert = newCert(@[newSubkey({ForSigning})]) let signedMessage = signMessage(cert.private, "Confidential Information") echo verifySignature(cert.public, signedMessage)