refactor: make CCN-STIC-221 enforcement opt-in via strictCrypto
Replace the always-on `allowLegacyEncryption` / default-on RSA checks with a single `strictCrypto` flag on both `SignOption` and `EncryptOption`. All modes and key lengths work by default; set `strictCrypto: true` to enforce the approved-algorithms rules. Update tests, externs, type declarations, and docs accordingly.pull/14/head
parent
162110c1fb
commit
a54166c901
75
README.md
75
README.md
|
|
@ -22,41 +22,62 @@ And I use this name to hope the merits from this application will be dedicated t
|
|||
* Sign a pdf with a timestamp from [TSA](https://github.com/zboris12/zgapdfsigner/wiki/API#note). ( :no_entry_sign:__Not__ available in web browser :sunflower:)
|
||||
* Enable signature's [LTV](https://github.com/zboris12/zgapdfsigner/wiki/API#note). ( :no_entry_sign:__Not__ available in web browser :sunflower:)
|
||||
* Set password protection to a pdf. Supported algorithms:
|
||||
* 256bit AES Encryption (default; the only algorithm allowed out of the box)
|
||||
* 128bit AES Encryption ( :warning: legacy, opt-in)
|
||||
* 128bit RC4 Encryption ( :warning: legacy, opt-in)
|
||||
* 40bit RC4 Encryption ( :warning: legacy, opt-in)
|
||||
* 40bit RC4 Encryption
|
||||
* 128bit RC4 Encryption
|
||||
* 128bit AES Encryption
|
||||
* 256bit AES Encryption
|
||||
* Set public-key certificate protection to a pdf.
|
||||
Supported algorithms are as same as the password protection.
|
||||
* Optionally enforce the algorithms approved by [CCN-STIC-221](https://www.ccn-cert.cni.es/).
|
||||
|
||||
## Cryptographic constraints (CCN-STIC-221)
|
||||
## Enforcing CCN-STIC-221 (optional)
|
||||
|
||||
This tool enforces the cryptographic requirements of
|
||||
[CCN-STIC-221](https://www.ccn-cert.cni.es/) by default. Two rules apply:
|
||||
[CCN-STIC-221](https://www.ccn-cert.cni.es/) is the approved-algorithms guide of
|
||||
the Spanish national cryptology centre. Set `strictCrypto: true` to make this
|
||||
tool refuse anything the guide does not authorize. __It is off by default, so
|
||||
nothing changes unless you ask for it.__
|
||||
|
||||
__1. Only AES-256 encryption is allowed.__ RC4 is a stream cipher and is not
|
||||
When it is on:
|
||||
|
||||
* __Only AES-256 encryption is accepted.__ RC4 is a stream cipher and is not
|
||||
authorized, and the RC4 / AES-128 PDF security handlers derive their key with
|
||||
MD5. Passing any other mode throws. Set `allowLegacyEncryption` to opt out when
|
||||
you need backward compatibility with old readers:
|
||||
|
||||
```js
|
||||
var eopt = {
|
||||
mode: Zga.Crypto.Mode.RC4_128,
|
||||
allowLegacyEncryption: true, // required, otherwise this throws
|
||||
userpwd: upwd,
|
||||
};
|
||||
```
|
||||
|
||||
__2. Signing keys must be RSA of at least 3000 bits, with log2(e) > 16.__
|
||||
A certificate carrying a shorter key (2048 bits, for example) is rejected when
|
||||
it is loaded. The standard public exponent 65537 already satisfies the exponent
|
||||
rule. Lower the modulus threshold with `minRsaKeyBits` if you must:
|
||||
MD5. Any other mode throws.
|
||||
* __Signing keys must be RSA of at least 3000 bits, with log2(e) > 16.__ A
|
||||
certificate carrying a shorter key is rejected when it is loaded. The standard
|
||||
public exponent 65537 already satisfies the exponent rule.
|
||||
|
||||
```js
|
||||
var sopt = {
|
||||
p12cert: cert,
|
||||
pwd: pwd,
|
||||
minRsaKeyBits: 2048, // accepts a 2048bit key; not CCN-STIC-221 compliant
|
||||
strictCrypto: true,
|
||||
};
|
||||
var eopt = {
|
||||
mode: Zga.Crypto.Mode.AES_256, // anything else throws under strictCrypto
|
||||
userpwd: upwd,
|
||||
};
|
||||
// strictCrypto on the SignOption also applies to the encryption step.
|
||||
var u8arr = await new Zga.PdfSigner(sopt).sign(pdf, eopt);
|
||||
```
|
||||
|
||||
`PdfCryptor` accepts the same flag when used on its own:
|
||||
|
||||
```js
|
||||
var cyptor = new Zga.PdfCryptor({
|
||||
mode: Zga.Crypto.Mode.AES_256,
|
||||
userpwd: upwd,
|
||||
strictCrypto: true,
|
||||
});
|
||||
```
|
||||
|
||||
`minRsaKeyBits` sets the minimum RSA modulus length. Setting it turns on the key
|
||||
length check on its own, and it overrides the 3000-bit default of `strictCrypto`:
|
||||
|
||||
```js
|
||||
var sopt = {
|
||||
p12cert: cert,
|
||||
pwd: pwd,
|
||||
minRsaKeyBits: 2048, // rejects keys under 2048bit; not CCN-STIC-221 compliant
|
||||
};
|
||||
```
|
||||
|
||||
|
|
@ -404,7 +425,7 @@ Set password protection to the pdf.
|
|||
async function protect1(pdf, upwd, opwd){
|
||||
/** @type {EncryptOption} */
|
||||
var eopt = {
|
||||
mode: Zga.Crypto.Mode.AES_256,
|
||||
mode: Zga.Crypto.Mode.RC4_40,
|
||||
permissions: ["modify", "annot-forms", "fill-forms", "extract", "assemble"],
|
||||
userpwd: upwd,
|
||||
ownerpwd: opwd,
|
||||
|
|
@ -427,7 +448,7 @@ Set public-key certificate protection to the pdf.
|
|||
async function protect2(pdf, cert){
|
||||
/** @type {EncryptOption} */
|
||||
var eopt = {
|
||||
mode: Zga.Crypto.Mode.AES_256,
|
||||
mode: Zga.Crypto.Mode.AES_128,
|
||||
pubkeys: [{
|
||||
c: cert,
|
||||
p: ["copy", "modify", "copy-extract", "annot-forms", "fill-forms", "extract", "assemble"],
|
||||
|
|
@ -458,7 +479,7 @@ async function signAndProtect1(pdf, cert, pwd, opwd){
|
|||
};
|
||||
/** @type {EncryptOption} */
|
||||
var eopt = {
|
||||
mode: Zga.Crypto.Mode.AES_256,
|
||||
mode: Zga.Crypto.Mode.RC4_128,
|
||||
permissions: ["modify", "annot-forms", "fill-forms", "extract", "assemble"],
|
||||
ownerpwd: opwd,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -95,8 +95,14 @@ var SignDrawInfo;
|
|||
* 1 : auto; Try using ocsp only to enable the LTV first; If can't, try using crl to enable the LTV.
|
||||
* 2 : crl only; Only try using crl to enable the LTV.
|
||||
*
|
||||
* minRsaKeyBits: Minimum accepted RSA modulus length in bits. Defaults to 3000
|
||||
* per CCN-STIC-221; signing keys shorter than this are rejected.
|
||||
* strictCrypto: Enforce the algorithms approved by CCN-STIC-221. Defaults to
|
||||
* false, which keeps the current behaviour. When true, signing keys must be
|
||||
* RSA of at least 3000 bits with a public exponent satisfying log2(e) > 16.
|
||||
* It also turns on strict encryption when an EncryptOption is passed to sign().
|
||||
*
|
||||
* minRsaKeyBits: Minimum accepted RSA modulus length in bits. Setting it enables
|
||||
* the key length check on its own and overrides the 3000-bit default of
|
||||
* strictCrypto.
|
||||
*
|
||||
* @typedef
|
||||
* {{
|
||||
|
|
@ -110,6 +116,7 @@ var SignDrawInfo;
|
|||
* signame: (string|undefined),
|
||||
* drawinf: (SignDrawInfo|undefined),
|
||||
* ltv: (number|undefined),
|
||||
* strictCrypto: (boolean|undefined),
|
||||
* minRsaKeyBits: (number|undefined),
|
||||
* debug: (boolean|undefined),
|
||||
* }}
|
||||
|
|
@ -140,7 +147,7 @@ var PubKeyInfo;
|
|||
*
|
||||
* pubkeys: Array of recipients containing public-key certificates ('c') and permissions ('p'). If want to encrypt the pdf by the certificate of signing, just apply a PubKeyInfo without c.
|
||||
*
|
||||
* allowLegacyEncryption: Allow non-authorized encryption modes (RC4-40, RC4-128, AES-128). Defaults to false; only AES-256 is accepted per CCN-STIC-221 unless this is set to true.
|
||||
* strictCrypto: Enforce the algorithms approved by CCN-STIC-221. Defaults to false, which keeps every encryption mode available. When true, only AES-256 is accepted.
|
||||
*
|
||||
* @typedef
|
||||
* {{
|
||||
|
|
@ -149,7 +156,7 @@ var PubKeyInfo;
|
|||
* userpwd: (string|undefined),
|
||||
* ownerpwd: (string|undefined),
|
||||
* pubkeys: (Array<PubKeyInfo>|undefined),
|
||||
* allowLegacyEncryption: (boolean|undefined),
|
||||
* strictCrypto: (boolean|undefined),
|
||||
* }}
|
||||
*/
|
||||
var EncryptOption;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export type EncryptOption = {
|
|||
userpwd?: string;
|
||||
ownerpwd?: string;
|
||||
pubkeys?: Array<PubKeyInfo>;
|
||||
allowLegacyEncryption?: boolean;
|
||||
strictCrypto?: boolean;
|
||||
};
|
||||
export type PubKeyInfo = {
|
||||
c?: Array<number> | Uint8Array | ArrayBuffer | string | forge.pki.Certificate;
|
||||
|
|
@ -78,6 +78,7 @@ export type SignOption = {
|
|||
signame?: string;
|
||||
drawinf?: SignDrawInfo;
|
||||
ltv?: number;
|
||||
strictCrypto?: boolean;
|
||||
minRsaKeyBits?: number;
|
||||
debug?: boolean;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -311,13 +311,12 @@ z.PdfCryptor = class{
|
|||
|
||||
// CCN-STIC-221: stream ciphers such as RC4 are not authorized,
|
||||
// and the MD5-based key derivation used by the RC4 / AES-128 PDF security
|
||||
// handlers is not authorized. Only the AES-256 handler avoids
|
||||
// both. Reject weaker modes unless the caller explicitly opts into legacy
|
||||
// encryption for backward compatibility.
|
||||
if(!encopt.allowLegacyEncryption && this.mode !== z.Crypto.Mode.AES_256){
|
||||
// handlers is not authorized. Only the AES-256 handler avoids both.
|
||||
// Enforcement is opt-in, so every existing mode keeps working by default.
|
||||
if(encopt.strictCrypto && this.mode !== z.Crypto.Mode.AES_256){
|
||||
throw new Error("Encryption mode " + this.mode + " is not authorized by "
|
||||
+ "CCN-STIC-221 (RC4 and MD5-based key derivation are prohibited). "
|
||||
+ "Use AES-256, or set allowLegacyEncryption:true to override.");
|
||||
+ "Use AES-256, or drop strictCrypto to allow legacy encryption.");
|
||||
}
|
||||
|
||||
/** @private @type {Array<string>|undefined} */
|
||||
|
|
|
|||
|
|
@ -487,6 +487,11 @@ z.PdfSigner = class{
|
|||
});
|
||||
}
|
||||
}
|
||||
// A signer asking for CCN-STIC-221 enforcement expects it to cover
|
||||
// the encryption too, unless the EncryptOption says otherwise.
|
||||
if(_this.opt.strictCrypto && cypopt.strictCrypto === undefined){
|
||||
cypopt.strictCrypto = true;
|
||||
}
|
||||
/** @type {Zga.PdfCryptor} */
|
||||
_this.cyptr = new z.PdfCryptor(cypopt);
|
||||
await _this.cyptr.encryptPdf(pdfdoc, encref);
|
||||
|
|
@ -739,21 +744,29 @@ z.PdfSigner = class{
|
|||
})[forge.pki.oids.pkcs8ShroudedKeyBag];
|
||||
_this.privateKey = keyBags[0].key;
|
||||
|
||||
// CCN-STIC-221: Reject shorter keys so a non-compliant certificate
|
||||
// cannot be used to sign. Override the minimum via opt.minRsaKeyBits.
|
||||
if(_this.privateKey && _this.privateKey.n){
|
||||
// CCN-STIC-221: Reject certificates whose RSA parameters are not approved,
|
||||
// so a non-compliant certificate cannot be used to sign. Enforcement is
|
||||
// opt-in via opt.strictCrypto, so existing callers are unaffected.
|
||||
// Setting opt.minRsaKeyBits enables the modulus check on its own and
|
||||
// overrides the 3000-bit default.
|
||||
if(_this.privateKey && _this.privateKey.n && _this.opt){
|
||||
/** @type {boolean} */
|
||||
var strictCrypto = !!_this.opt.strictCrypto;
|
||||
/** @type {boolean} */
|
||||
var hasMinRsaKeyBits = typeof _this.opt.minRsaKeyBits === "number";
|
||||
if(strictCrypto || hasMinRsaKeyBits){
|
||||
/** @type {number} */
|
||||
var minRsaKeyBits = (_this.opt && typeof _this.opt.minRsaKeyBits === "number")
|
||||
? _this.opt.minRsaKeyBits : 3000;
|
||||
var minRsaKeyBits = hasMinRsaKeyBits ? _this.opt.minRsaKeyBits : 3000;
|
||||
/** @type {number} */
|
||||
var rsaKeyBits = _this.privateKey.n.bitLength();
|
||||
if(rsaKeyBits < minRsaKeyBits){
|
||||
throw new Error("RSA key length " + rsaKeyBits + " bits is below the "
|
||||
+ minRsaKeyBits + "-bit minimum required by CCN-STIC-221.");
|
||||
}
|
||||
}
|
||||
// CCN-STIC-221 requires the public exponent to satisfy log2(e) > 16.
|
||||
// The de-facto standard value 65537 already meets this.
|
||||
if(_this.privateKey.e && _this.privateKey.e.bitLength() <= 16){
|
||||
if(strictCrypto && _this.privateKey.e && _this.privateKey.e.bitLength() <= 16){
|
||||
throw new Error("RSA public exponent is too small; CCN-STIC-221 requires log2(e) > 16.");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "zgapdfsigner",
|
||||
"version": "3.0.0",
|
||||
"version": "2.8.0",
|
||||
"author": "zboris12",
|
||||
"description": "A javascript tool to sign a pdf or set protection to a pdf in web browser, Google Apps Script and nodejs.",
|
||||
"homepage": "https://github.com/zboris12/zgapdfsigner",
|
||||
|
|
|
|||
|
|
@ -7,36 +7,39 @@ const Zga = require("../lib/zganode.js");
|
|||
const Mode = Zga.Crypto.Mode;
|
||||
|
||||
// CCN-STIC-221: RC4 (any stream cipher) and MD5-based key derivation are not
|
||||
// authorized. Only the AES-256 handler avoids both. The production change that
|
||||
// makes these fail is removing the mode guard added in the PdfCryptor constructor.
|
||||
// authorized. Only the AES-256 handler avoids both. Enforcement is opt-in via
|
||||
// strictCrypto, so the default stays backward compatible. The production change
|
||||
// that makes these fail is removing the mode guard in the PdfCryptor constructor.
|
||||
|
||||
test("rejects RC4-40 encryption by default", () => {
|
||||
test("allows every legacy mode by default", () => {
|
||||
assert.doesNotThrow(() => new Zga.PdfCryptor({mode: Mode.RC4_40, userpwd: "x"}));
|
||||
assert.doesNotThrow(() => new Zga.PdfCryptor({mode: Mode.RC4_128, userpwd: "x"}));
|
||||
assert.doesNotThrow(() => new Zga.PdfCryptor({mode: Mode.AES_128, userpwd: "x"}));
|
||||
});
|
||||
|
||||
test("rejects RC4-40 encryption under strictCrypto", () => {
|
||||
assert.throws(
|
||||
() => new Zga.PdfCryptor({mode: Mode.RC4_40, userpwd: "x"}),
|
||||
() => new Zga.PdfCryptor({mode: Mode.RC4_40, userpwd: "x", strictCrypto: true}),
|
||||
/not authorized by CCN-STIC-221/,
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects RC4-128 encryption by default", () => {
|
||||
test("rejects RC4-128 encryption under strictCrypto", () => {
|
||||
assert.throws(
|
||||
() => new Zga.PdfCryptor({mode: Mode.RC4_128, userpwd: "x"}),
|
||||
() => new Zga.PdfCryptor({mode: Mode.RC4_128, userpwd: "x", strictCrypto: true}),
|
||||
/not authorized by CCN-STIC-221/,
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects AES-128 encryption by default", () => {
|
||||
test("rejects AES-128 encryption under strictCrypto", () => {
|
||||
assert.throws(
|
||||
() => new Zga.PdfCryptor({mode: Mode.AES_128, userpwd: "x"}),
|
||||
() => new Zga.PdfCryptor({mode: Mode.AES_128, userpwd: "x", strictCrypto: true}),
|
||||
/not authorized by CCN-STIC-221/,
|
||||
);
|
||||
});
|
||||
|
||||
test("accepts AES-256 encryption", () => {
|
||||
assert.doesNotThrow(() => new Zga.PdfCryptor({mode: Mode.AES_256, userpwd: "x"}));
|
||||
});
|
||||
|
||||
test("allows legacy modes only when allowLegacyEncryption is set", () => {
|
||||
test("accepts AES-256 encryption under strictCrypto", () => {
|
||||
assert.doesNotThrow(
|
||||
() => new Zga.PdfCryptor({mode: Mode.RC4_128, userpwd: "x", allowLegacyEncryption: true}),
|
||||
() => new Zga.PdfCryptor({mode: Mode.AES_256, userpwd: "x", strictCrypto: true}),
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,43 +8,66 @@ const {makeP12} = require("../testutil/fixtures.js");
|
|||
const PWD = "test-pw";
|
||||
|
||||
// CCN-STIC-221: RSA modulus must be >= 3000 bits and the public exponent must
|
||||
// satisfy log2(e) > 16. The production change that makes these fail is removing
|
||||
// the corresponding guard added in PdfSigner.loadP12cert.
|
||||
// satisfy log2(e) > 16. Enforcement is opt-in via strictCrypto, except that
|
||||
// setting minRsaKeyBits enables the modulus check on its own. The production
|
||||
// change that makes these fail is removing the corresponding guard in
|
||||
// PdfSigner.loadP12cert.
|
||||
|
||||
test("rejects an RSA key shorter than 3000 bits", () => {
|
||||
test("accepts a short RSA key by default", () => {
|
||||
const p12 = makeP12(2048, PWD);
|
||||
const signer = new Zga.PdfSigner({});
|
||||
assert.doesNotThrow(() => signer.loadP12cert(p12, PWD));
|
||||
});
|
||||
|
||||
test("rejects an RSA key shorter than 3000 bits under strictCrypto", () => {
|
||||
const p12 = makeP12(2048, PWD);
|
||||
const signer = new Zga.PdfSigner({strictCrypto: true});
|
||||
assert.throws(
|
||||
() => signer.loadP12cert(p12, PWD),
|
||||
/below the 3000-bit minimum/,
|
||||
);
|
||||
});
|
||||
|
||||
test("accepts an RSA key of 3072 bits", () => {
|
||||
test("accepts an RSA key of 3072 bits under strictCrypto", () => {
|
||||
const p12 = makeP12(3072, PWD);
|
||||
const signer = new Zga.PdfSigner({});
|
||||
const signer = new Zga.PdfSigner({strictCrypto: true});
|
||||
assert.doesNotThrow(() => signer.loadP12cert(p12, PWD));
|
||||
});
|
||||
|
||||
test("honors a custom minRsaKeyBits threshold below the default", () => {
|
||||
const p12 = makeP12(2048, PWD);
|
||||
test("minRsaKeyBits enforces the key length without strictCrypto", () => {
|
||||
const p12 = makeP12(1024, PWD);
|
||||
const signer = new Zga.PdfSigner({minRsaKeyBits: 2048});
|
||||
assert.throws(
|
||||
() => signer.loadP12cert(p12, PWD),
|
||||
/below the 2048-bit minimum/,
|
||||
);
|
||||
});
|
||||
|
||||
test("minRsaKeyBits overrides the strictCrypto default", () => {
|
||||
const p12 = makeP12(2048, PWD);
|
||||
const signer = new Zga.PdfSigner({strictCrypto: true, minRsaKeyBits: 2048});
|
||||
assert.doesNotThrow(() => signer.loadP12cert(p12, PWD));
|
||||
});
|
||||
|
||||
// The modulus check runs first, so minRsaKeyBits is lowered here purely to let
|
||||
// a cheap-to-generate key reach the exponent check.
|
||||
test("rejects an RSA public exponent with log2(e) <= 16", () => {
|
||||
test("rejects an RSA public exponent with log2(e) <= 16 under strictCrypto", () => {
|
||||
const p12 = makeP12(1024, PWD, 3);
|
||||
const signer = new Zga.PdfSigner({minRsaKeyBits: 1024});
|
||||
const signer = new Zga.PdfSigner({strictCrypto: true, minRsaKeyBits: 1024});
|
||||
assert.throws(
|
||||
() => signer.loadP12cert(p12, PWD),
|
||||
/public exponent is too small/,
|
||||
);
|
||||
});
|
||||
|
||||
test("accepts the standard 65537 public exponent", () => {
|
||||
const p12 = makeP12(1024, PWD, 65537);
|
||||
test("accepts a small public exponent when strictCrypto is off", () => {
|
||||
const p12 = makeP12(1024, PWD, 3);
|
||||
const signer = new Zga.PdfSigner({minRsaKeyBits: 1024});
|
||||
assert.doesNotThrow(() => signer.loadP12cert(p12, PWD));
|
||||
});
|
||||
|
||||
test("accepts the standard 65537 public exponent under strictCrypto", () => {
|
||||
const p12 = makeP12(1024, PWD, 65537);
|
||||
const signer = new Zga.PdfSigner({strictCrypto: true, minRsaKeyBits: 1024});
|
||||
assert.doesNotThrow(() => signer.loadP12cert(p12, PWD));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -50,12 +50,36 @@ test("PdfSigner.sign encrypts the output when an AES-256 EncryptOption is given"
|
|||
assert.match(dump, /adbe\.pkcs7\.detached/, "still carries the detached signature");
|
||||
});
|
||||
|
||||
test("PdfSigner.sign refuses a legacy encryption mode", async () => {
|
||||
test("PdfSigner.sign accepts a legacy encryption mode by default", async () => {
|
||||
const pdfBytes = await minimalPdf();
|
||||
const signer = new Zga.PdfSigner({p12cert: makeP12(3072, PWD), pwd: PWD});
|
||||
|
||||
const signed = await signer.sign(pdfBytes, {mode: Zga.Crypto.Mode.RC4_128, userpwd: "user-pw"});
|
||||
|
||||
assert.match(Buffer.from(signed).toString("latin1"), /\/Encrypt/);
|
||||
});
|
||||
|
||||
// strictCrypto on the SignOption has to reach the cryptor, otherwise a caller
|
||||
// asking for compliance would silently get a non-compliant encryption handler.
|
||||
test("PdfSigner.sign propagates strictCrypto to the encryption step", async () => {
|
||||
const pdfBytes = await minimalPdf();
|
||||
const signer = new Zga.PdfSigner({p12cert: makeP12(3072, PWD), pwd: PWD, strictCrypto: true});
|
||||
|
||||
await assert.rejects(
|
||||
() => signer.sign(pdfBytes, {mode: Zga.Crypto.Mode.RC4_128, userpwd: "user-pw"}),
|
||||
/not authorized by CCN-STIC-221/,
|
||||
);
|
||||
});
|
||||
|
||||
test("an explicit strictCrypto on the EncryptOption wins over the SignOption", async () => {
|
||||
const pdfBytes = await minimalPdf();
|
||||
const signer = new Zga.PdfSigner({p12cert: makeP12(3072, PWD), pwd: PWD, strictCrypto: true});
|
||||
|
||||
const signed = await signer.sign(pdfBytes, {
|
||||
mode: Zga.Crypto.Mode.RC4_128,
|
||||
userpwd: "user-pw",
|
||||
strictCrypto: false,
|
||||
});
|
||||
|
||||
assert.match(Buffer.from(signed).toString("latin1"), /\/Encrypt/);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue