Is it possible to use XML Crypto using a PSHA1 (http://schemas.xmlsoap.org/ws/2005/02/trust/CK/PSHA1) key?
I have both secrets and generate a PSHA1 key string using them, however this fails with:
Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
I'm not what format this key needs to be in to be accepted, it's not a PEM certificate, just a string based on 2 provided nonce's. One provided by the client during the request and one provided by the server in the response.
const sig = new SignedXml();
sig.addReference("/*[local-name()='Envelope']/*[local-name()='Header']/*[local-name()='Security']/*[local-name()='Timestamp']");
sig.signingKey = '<SIGNING_KEY>';
sig.computeSignature(xml);
fs.writeFileSync('signed.xml', sig.getSignedXml());
It fails on the signer.sign line here:
this.getSignature = function(signedInfo, signingKey) {
var signer = crypto.createSign("RSA-SHA1")
signer.update(signedInfo)
var res = signer.sign(signingKey, 'base64')
return res
}
The PSHA1 algorithm isn't implemented in the Crypto Library, but there's a PSHA1 npm package you can use to generate the secret key. After that you can generate a SHA1 hash using the message and key in the standard way.
I asked a very similar question here, which answers the question:
https://stackoverflow.com/a/55053741/5065447
Related
I am trying to create a digitally signed XML document using the signature from my ID card.
I have two parts of the program. The first one is getting the certificates and signature of the file from the ID.
For that I am using python PKCS11 library with something like this:
with open("input.xml", "rb") as f:
data = f.read()
lib = lib('path/to/pkcs11/lib.dylib')
token = lib.get_token('name of token')
with token.open(PIN) as session:
certificate = None
for obj in session.get_objects({Attribute.CLASS: ObjectClass.CERTIFICATE}):
certificate = obj
der_bytes = certificate[Attribute.VALUE]
with open('certificate.der', "wb") as f:
f.write(der_bytes)
# calculate SHA256 of data
digest = session.digest(data, mechanism=Mechanism.SHA256)
for obj in session.get_objects({Attribute.CLASS: ObjectClass.PRIVATE_KEY}):
private_key = obj
signature = private_key.sign(digest, mechanism=Mechanism.RSA_PKCS)
with open('signature', "wb") as f:
f.write(signature)
That generates the certificate.der and signature files and is working properly (at least I think)
For the XML generation part I am using Europe's DSS library in Java like this:
DSSDocument toSignDocument = new FileDocument("input.xml");
// Preparing parameters for the XAdES signature
XAdESSignatureParameters parameters = new XAdESSignatureParameters();
// We choose the level of the signature (-B, -T, -LT, -LTA).
parameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_B);
// We choose the type of the signature packaging (ENVELOPED, ENVELOPING, DETACHED).
parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED);
// We set the digest algorithm to use with the signature algorithm. You must use the
// same parameter when you invoke the method sign on the token. The default value is SHA256 parameters.setDigestAlgorithm(DigestAlgorithm.SHA256);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new FileInputStream("certificate.der");
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);
// We set the signing certificate
parameters.setSigningCertificate(new CertificateToken(cert));
// Create common certificate verifier
CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier();
// Create XAdES service for signature
XAdESService service = new XAdESService(commonCertificateVerifier);
// Get the SignedInfo XML segment that need to be signed.
ToBeSigned dataToSign = service.getDataToSign(toSignDocument, parameters);
File file = new File("signature");
SignatureValue signatureValue = new SignatureValue(SignatureAlgorithm.RSA_SHA256, Files.readAllBytes(file.toPath()));
// We invoke the service to sign the document with the signature value obtained in
// the previous step.
DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);
File signedFile = new File("output.xml");
signedFile.createNewFile();
signedDocument.writeTo(new FileOutputStream(signedFile, false));
That creates XAdES file, but when I try to validate the signature (e.g. using this) it fails saying the signature is not intact.
What am I doing wrong?
You do not use dataToSign variable at all for signature value creation.
What you should do is by using the private key corresponding to the created certificate to actually sign the digested dataToSign. I.e., instead of:
File file = new File("signature");
SignatureValue signatureValue = new SignatureValue(SignatureAlgorithm.RSA_SHA256, Files.readAllBytes(file.toPath()));
you should do something like this (using your example above):
# calculate SHA256 of data
digest = session.digest(dataToSign, mechanism=Mechanism.SHA256)
for obj in session.get_objects({Attribute.CLASS: ObjectClass.PRIVATE_KEY}):
private_key = obj
signatureValue = private_key.sign(digest, mechanism=Mechanism.RSA_PKCS)
Please pay attention, that you shall sign not the original document, but the dataToSign, as it contains the reference to the original document (its digest), but also signed parameters, required to ensure compliance to AdES format.
I hope this will help you.
Best regards,
Aleksandr.
I am trying to encrypt a value on my server with a private key to store it on the client within an httpOnly cookie.
I am having trouble with the encryption/decryption lifecycle
function encrypt(input) {
const encryptedData = crypto.privateEncrypt(
privateKey,
Buffer.from(input)
)
return encryptedData.toString('base64')
}
function decrypt(input) {
const decryptedData = crypto.privateDecrypt(
{ key: privateKey },
Buffer.from(input, 'base64'),
)
return decryptedData.toString()
}
const enc = encrypt('something moderately secret')
const dec = decrypt(enc)
console.log(dec) // 'something moderately secret'
However the crypto.privateDecrypt function is throwing with
Error: error:04099079:rsa routines:RSA_padding_check_PKCS1_OAEP_mgf1:oaep decoding error
Side question, is it safe to reuse the same private key the server uses to sign JWTs. It's an rsa key generated using ssh-keygen -t rsa -b 4096 -m PEM -f RS256.key
So, you don't use crypto.privateEncrypt() with crypto.privateDecrypt(). That's not how they work. Those functions are for asymmetric encryption, not for symmetric encryption. You use either of these two pairs:
crypto.publicEncrypt() ==> crypto.privateDescrypt()
crypto.privateEncrypt() ==> crypto.publicDecrypt()
So, that's why you're getting the error you're getting. The nodejs doc for crypto.privateDecript() says this:
Decrypts buffer with privateKey. buffer was previously encrypted using the corresponding public key, for example using crypto.publicEncrypt().
If what you really want is symmetric encryption, there are a bunch of options in the crypto module for that. There are some examples shown here: https://www.section.io/engineering-education/data-encryption-and-decryption-in-node-js-using-crypto/ and https://fireship.io/lessons/node-crypto-examples/#symmetric-encryption-in-nodejs.
I have a public key string as follows
let pk_str = "public key strig here" and I am using the library jose to verify a JWS
(async() => {
const decoder = new TextDecoder();
const jws = vc_proof_value;
const { payload, protectedHeader } = await compactVerify(jws, pk_str);
console.log(protectedHeader)
console.log(decoder.decode(payload))
})();
I am getting the following error when trying to run the script
(node:75986) UnhandledPromiseRejectionWarning: TypeError: Key must be one of type KeyObject, CryptoKey, or Uint8Array. Received type string
Is there a way to construct the key ?
In NodeJS (I refer to NodeJS, since you have tagged this), the public key is passed as KeyObject wich is created with crypto.createPublicKey(). You didn't say much about the key, presumably it's PEM encoded (since it's a string). In this case, you simply have to pass the PEM encoded key:
var key = crypto.createPublicKey(pk_str);
If in the compactVerify() call pk_str is replaced by key, verification works.
In addition to PEM keys (default), JWK and DER keys (X.509/SPKI or PKCS#1) are also supported.
Here is the documentation for the key argument of all applicable functions.
I've been creating a gateway for a legacy service, this legacy service needs a signature as a body parameter of a PUT request, in order to create this sign I need to follow the following steps:
Create a hash with certain text as data, this hash needs to be SHA256.
Encrypt the result of the hash using RSA with a PEM key
Encode the result of the RSA to Base64
Following the previous steps I create the following code
export class Signature {
// class body
public static sign(text: string){
const key = readFileSync('key.pem')
const passphrase = '12345678'
const createdSign = createSign('RSA-SHA256')
createdSign.write(text)
createdSign.end()
return createdSign.sign({ key, passphrase }).toString('base64')
}
}
But I'm not sure if this the correct implementation, taking into consideration the previous steps, and the existence of the hash API in NodeJS.
If someone could tell me if I'm correctly implementing this algorithm.
I have a signed pdf I am attaching a certificate(.pfx) to the document through itextsharp. Everything in the code is tested and working fine but when I download and open the pdf in acrobat reader it says the signature is not valid I have changed preferences tried almost every setting since yesterday but there isn't any luck.
two things I noticed in certificate detail that for its "intended" property: the DIGITAL signature is not mentioned whereas encrypt document etc is mentioned is this the reason it is not validating the document for signature.
and the second thing it says: certificate has error: not valid for usage
code for attaching certificate;
var pathCert =
Server.MapPath("..../App_Data/Certificates/.....sdd.pfx");
string Password = "**************";
var pass = Password.ToCharArray();
System.Security.Cryptography.X509Certificates.X509Store store =
new System.Security.Cryptography.X509Certificates.X509Store
(Cryptography.X509Certificates.StoreLocation.CurrentUser);
store.Open(System.Security.
Cryptography.X509Certificates.OpenFlags.ReadOnly);
string PfxFileName = pathCert;
string PfxPassword = Password;
System.Security.Cryptography.X509Certificates.X509Certificate2 cert = new
System.Security.Cryptography.X509Certificates.X509Certificate2
(PfxFileName, PfxPassword, Security.Cryptography.X509Certificates.
X509KeyStorageFlags.MachineKeySet);
string SourcePdfFileName = "(Directory)/Desktop/tetsing/test.pdf";
string DestPdfFileName = "(Directory)/Desktop/tetsing/test_Signed.pdf";
Org.BouncyCastle.X509.X509CertificateParser cp = new
Org.BouncyCastle.X509.X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new
Org.BouncyCastle.X509.X509Certificate[] {
cp.ReadCertificate(cert.RawData) };
iTextSharp.text.pdf.security.IExternalSignature externalSignature = new
iTextSharp.text.pdf.security.X509Certificate2Signature(cert, "SHA-1");
PdfReader pdfReader = new PdfReader(SourcePdfFileName);
FileStream signedPdf = new FileStream(DestPdfFileName, FileMode.Create);
//the output pdf file
PdfStamper pdfStamper = PdfStamper.CreateSignature(pdfReader, signedPdf,
'\0');
PdfSignatureAppearance signatureAppearance =
pdfStamper.SignatureAppearance;
signatureAppearance.Reason = "Signed Document";
signatureAppearance.Location = "Unknown";
signatureAppearance.SignatureRenderingMode =
PdfSignatureAppearance.RenderingMode.DESCRIPTION;
MakeSignature.SignDetached(signatureAppearance, externalSignature,
chain,
null, null, null, 0, CryptoStandard.CMS);
pdfReader.Close();
Adobe acrobat reader is very picky on the certificate key usage and intended purpose (Key Usage and Enhanced Key Usage) and other details of the certificate. Have you tried a certificate with Digital Signature as key usage and Code Signing as intended purpose?
Here is a blog post that shows how to self sign a certificate with that properties for doing signatures if you do not have access to a real publicly trusted signing certificate.
certificate has error: not valid for usage
According to the Adobe Digital Signatures Guide for IT, Adobe Acrobat accepts only
one or more of the following Key usage values (if any)
nonRepudiation
signTransaction (11.0.09 only)
digitalSignature (11.0.10 and later)
and one or more of the following Extended key usage values (if any)
emailProtection
codeSigning
anyExtendedKeyUsage
1.2.840.113583.1.1.5 (Adobe Authentic Documents Trust)
Please check your certificate accordingly and replace it if it does not fulfill this condition.