nimcypher/algos/rsa

NOTE: no =destroy hook is installed on purpose: the BigInt-backed fields live in managed seqs, so an implicit destructor already exists; call wipe explicitly when done with a private key.

Types

RsaHash = enum
  rhSha1, rhSha256, rhSha384, rhSha512
Hash paired with an RSA padding. rhSha1 is only valid for OAEP (RSA-OAEP); signatures use SHA-2.
RsaPrivateKey = object
  n*: BigInt
  e*: BigInt
  d*: BigInt
  p*: BigInt
  q*: BigInt
  dp*: BigInt
  dq*: BigInt
  qinv*: BigInt
  k*: int
RsaPublicKey = object
  n*: BigInt
  e*: BigInt
  k*: int                    ## modulus byte length (I2OSP width)

Procs

proc generateRsaKeyPair(bits = 2048; e = 65537; allowSmallKeys = false): RsaPrivateKey {.
    ...raises: [ValueError, OSError, Exception], tags: [RootEffect], forbids: [].}
Generate an RSA key pair. bits is the modulus size (default 2048). e defaults to 65537. Sizes below 2048 are insecure and rejected unless allowSmallKeys is set (tests only, never production keys).
func hashLen(h: RsaHash): int {....raises: [], tags: [], forbids: [].}
proc oaepDecrypt(key: RsaPrivateKey; h: RsaHash; cipher: openArray[byte];
                 label: openArray[byte] = []): seq[byte] {.
    ...raises: [ValueError, Exception, OSError], tags: [RootEffect], forbids: [].}
RSAES-OAEP decrypt. Raises ValueError("decryption error") on failure. Failure messages are uniform, but the decode still branches on padding validity (non-uniform timing): callers must not let attackers measure decrypt timing (known limitation, full constant-time decode is follow-up work).
proc oaepEncrypt(key: RsaPublicKey; h: RsaHash; msg: openArray[byte];
                 label: openArray[byte] = []): seq[byte] {.
    ...raises: [ValueError, OSError, Exception], tags: [RootEffect], forbids: [].}
RSAES-OAEP encrypt. rhSha1 = JWA RSA-OAEP, rhSha256 = RSA-OAEP-256.
proc pkcs1v15Decrypt(key: RsaPrivateKey; cipher: openArray[byte]): seq[byte] {.
    ...raises: [ValueError, Exception, OSError], tags: [RootEffect], forbids: [].}
RSAES-PKCS1-v1_5 decrypt. Raises ValueError("decryption error"). Same timing caveat as oaepDecrypt: uniform messages, but padding-validity branching is not constant-time, so decrypt timing must stay hidden from attackers.
proc pkcs1v15Encrypt(key: RsaPublicKey; msg: openArray[byte]): seq[byte] {.
    ...raises: [ValueError, OSError, Exception], tags: [RootEffect], forbids: [].}
RSAES-PKCS1-v1_5 encrypt (JWA RSA1_5).
proc pkcs1v15Sign(key: RsaPrivateKey; h: RsaHash; msg: openArray[byte]): seq[
    byte] {....raises: [ValueError, Exception, OSError], tags: [RootEffect],
            forbids: [].}
RSASSA-PKCS1-v1_5 sign (JWA RS256/384/512). The signature is verified with the public operation before return (fault-attack mitigation: a faulted CRT computation raises instead of leaking a Bellcore-oracle signature).
proc pkcs1v15Verify(key: RsaPublicKey; h: RsaHash; msg: openArray[byte];
                    sig: openArray[byte]): bool {.
    ...raises: [ValueError, Exception], tags: [RootEffect], forbids: [].}
RSASSA-PKCS1-v1_5 verify. Returns false (no exception) on bad signature. SHA-1 is not a valid signature hash here: it returns false rather than raising, so verifiers never throw on attacker-controlled inputs.
proc pssSign(key: RsaPrivateKey; h: RsaHash; msg: openArray[byte]): seq[byte] {.
    ...raises: [ValueError, OSError, Exception], tags: [RootEffect], forbids: [].}
RSASSA-PSS sign with saltLen = hashLen (JWA PS256/384/512). The signature is verified with the public operation before return (fault-attack mitigation, see pkcs1v15Sign).
proc pssVerify(key: RsaPublicKey; h: RsaHash; msg: openArray[byte];
               sig: openArray[byte]): bool {....raises: [ValueError, Exception],
    tags: [RootEffect], forbids: [].}
RSASSA-PSS verify (saltLen recovered, must equal hashLen per JWA).
proc publicKey(key: RsaPrivateKey): RsaPublicKey {....raises: [], tags: [],
    forbids: [].}
proc rsaPrivateKey(n, e, d, p, q: BigInt): RsaPrivateKey {.
    ...raises: [ValueError, Exception], tags: [RootEffect], forbids: [].}
proc rsaPublicKey(n, e: BigInt): RsaPublicKey {....raises: [ValueError], tags: [],
    forbids: [].}
proc wipe(key: var RsaPrivateKey) {....raises: [], tags: [], forbids: [].}
Best-effort wipe of private material. pkg/bigints keeps limbs in a managed seq, so this drops all references (GC frees the backing buffers); it does not scrub freed memory. Ephemeral buffers (seq[byte]) elsewhere in this module ARE scrubbed via wipe.