bugl
bugl
HomeLearnPatternsSearch
HomeLearnPatternsSearch

Loading lesson path

Learn/Node.js/Node.js Reference
Node.js•Node.js Reference

Node.js Verify Reference

Concept visual

Node.js Verify Reference

Graph traversalgraph
ABCDE
current
queued
1
4

Start from A

Verify Object

The Verify class is part of Node.js's crypto module. It provides a way to verify cryptographic digital signatures. Verify instances are created using the crypto.createVerify() method. Verify is used in conjunction with the Sign class to validate that a message was signed by a known sender and was not altered in transit.

Import Crypto Module

// Import the crypto module const crypto = require('crypto');
// Create a Verify object const verify = crypto.createVerify('RSA-SHA256');

Verify Methods

Method

Description verify.update(data[, inputEncoding])

Updates the Verify content with the given data. If inputEncoding is provided, data is a string using the specified encoding; otherwise, data is a Buffer, TypedArray, or DataView. This method can be called multiple times with new data.
verify.verify(object, signature[, signatureEncoding])

Verifies the provided data using the given object and signature.

object is a string containing a PEM-encoded public key, a KeyObject of type 'public', or an X.509 certificate. If signatureEncoding is provided, signature is a string using the specified encoding; otherwise it is a Buffer, TypedArray, or DataView. Returns true if the signature is valid, false otherwise.

Basic Verify Example

The following example demonstrates how to verify a digital signature of a message:

const crypto = require('crypto');
const fs = require('fs');
// Load the message, signature, and public key

// In a real application, these would typically come from files or network

// For this example, we'll try to load from the files created in the Sign example let message, signature, publicKey;
try {
message = fs.readFileSync('message.txt', 'utf8');
signature = fs.readFileSync('signature.hex', 'utf8');
publicKey = fs.readFileSync('public_key.pem', 'utf8');
} catch (error) {
// If files don't exist, create example data const { privateKey, publicKey: newPublicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048, publicKeyEncoding: {
type: 'spki', format: 'pem'
}, privateKeyEncoding: {
type: 'pkcs8', format: 'pem'
}
});
message = 'This is a message to be verified';
publicKey = newPublicKey;
// Create a signature for the example const sign = crypto.createSign('SHA256');
sign.update(message);
signature = sign.sign(privateKey, 'hex');
}
// Create a Verify object const verify = crypto.createVerify('SHA256');
// Update with the message verify.update(message);
// Verify the signature with the public key const isValid = verify.verify(publicKey, signature, 'hex');
console.log('Message:', message);
console.log('Signature:', signature);
console.log('Is signature valid?', isValid);

Verifying with Different Algorithms

The Verify class supports various signature algorithms:

const crypto = require('crypto');
// Generate key pairs for different algorithms function generateRSAKeyPair() {
return crypto.generateKeyPairSync('rsa', {
modulusLength: 2048, publicKeyEncoding: {
type: 'spki', format: 'pem'
}, privateKeyEncoding: {
type: 'pkcs8', format: 'pem'
}
});
}
function generateECKeyPair() {
return crypto.generateKeyPairSync('ec', {
namedCurve: 'prime256v1', publicKeyEncoding: {
type: 'spki', format: 'pem'
}, privateKeyEncoding: {
type: 'sec1', format: 'pem'
}
});
}
// Generate different key pairs const rsaKeys = generateRSAKeyPair();
const ecKeys = generateECKeyPair();
// Message to sign and verify const message = 'Message to verify with different algorithms';
// Function to sign and verify with a specific algorithm function testSignatureVerification(algorithm, privateKey, publicKey, message) {
try {
// Sign the message const sign = crypto.createSign(algorithm);
sign.update(message);
const signature = sign.sign(privateKey, 'hex');
// Verify the signature const verify = crypto.createVerify(algorithm);
verify.update(message);
const isValid = verify.verify(publicKey, signature, 'hex');
// Try to verify with a tampered message const tamperedVerify = crypto.createVerify(algorithm);
tamperedVerify.update(message + ' (tampered)');
const isTamperedValid = tamperedVerify.verify(publicKey, signature, 'hex');
return {

algorithm, isValid, isTamperedValid

};
} catch (error) {
return {

algorithm, error: error.message

};
}
}
// Test various signature algorithms console.log(`Message: "${message}"`);
console.log('-----------------------------------------------');
// RSA signatures with different hash algorithms console.log('RSA Signatures:');
['SHA256', 'SHA384', 'SHA512'].forEach(hash => {
console.log(testSignatureVerification(hash, rsaKeys.privateKey, rsaKeys.publicKey, message));
});
console.log('-----------------------------------------------');
// ECDSA signatures console.log('ECDSA Signatures:');
['SHA256', 'SHA384'].forEach(hash => {
console.log(testSignatureVerification(hash, ecKeys.privateKey, ecKeys.publicKey, message));
});

Verifying with Multiple Updates

You can update a Verify object with multiple pieces of data:

const crypto = require('crypto');
// Generate a keypair const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048, publicKeyEncoding: {
type: 'spki', format: 'pem'
}, privateKeyEncoding: {
type: 'pkcs8', format: 'pem'
}
});
// Create a signature with multiple updates const sign = crypto.createSign('SHA256');
sign.update('First part of the message. ');
sign.update('Second part of the message. ');
sign.update('Third part of the message.');
const signature = sign.sign(privateKey, 'hex');
console.log('Signature created with multiple updates');
// Create a Verify object const verify = crypto.createVerify('SHA256');
// Verify with multiple updates matching the original verify.update('First part of the message. ');
verify.update('Second part of the message. ');
verify.update('Third part of the message.');
const isValidMultiple = verify.verify(publicKey, signature, 'hex');
console.log('Verification with matching multiple updates:', isValidMultiple);
// Verify with a single update containing the same data const verifySingle = crypto.createVerify('SHA256');
verifySingle.update('First part of the message. Second part of the message. Third part of the message.');
const isValidSingle = verifySingle.verify(publicKey, signature, 'hex');
console.log('Verification with single update of same data:', isValidSingle);
// Try to verify with different updates const verifyDifferent = crypto.createVerify('SHA256');
verifyDifferent.update('First part of the message. ');
verifyDifferent.update('Modified second part. ');
verifyDifferent.update('Third part of the message.');
const isValidDifferent = verifyDifferent.verify(publicKey, signature, 'hex');
console.log('Verification with different updates:', isValidDifferent);

Verifying File Signatures

This example demonstrates verifying a digital signature for a file:

const crypto = require('crypto');
const fs = require('fs');
// Function to verify a file's signature function verifyFile(filePath, signaturePath, publicKey, algorithm = 'SHA256') {
return new Promise((resolve, reject) => {
try {
// Read the signature const signature = fs.readFileSync(signaturePath, 'utf8');
// Create Verify object const verify = crypto.createVerify(algorithm);
// Create read stream for the file const readStream = fs.createReadStream(filePath);
// Handle stream events readStream.on('data', (data) => {
verify.update(data);
});
readStream.on('end', () => {
// Verify the signature const isValid = verify.verify(publicKey, signature, 'hex');
resolve(isValid);
});
readStream.on('error', (error) => {
reject(error);
});
} catch (error) {
reject(error);
}
});
}
// For this example, create a file, sign it, and verify it const filePath = 'example_to_verify.txt';
const signaturePath = `${filePath}.sig`;
const publicKeyPath = 'verify_public_key.pem';
// Create a test environment if files don't exist if (!fs.existsSync(filePath) || !fs.existsSync(signaturePath) || !fs.existsSync(publicKeyPath)) {
console.log('Creating test environment...');
// Generate a keypair const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048, publicKeyEncoding: {
type: 'spki', format: 'pem'
}, privateKeyEncoding: {
type: 'pkcs8', format: 'pem'
}
});
// Save the public key fs.writeFileSync(publicKeyPath, publicKey);
// Create a test file fs.writeFileSync(filePath, 'This is a test file for signature verification.\n'.repeat(100));
// Sign the file const sign = crypto.createSign('SHA256');
const fileContent = fs.readFileSync(filePath);
sign.update(fileContent);
const signature = sign.sign(privateKey, 'hex');
// Save the signature fs.writeFileSync(signaturePath, signature);
console.log('Test environment created');
}
// Load the public key const publicKey = fs.readFileSync(publicKeyPath, 'utf8');
// Verify the file signature verifyFile(filePath, signaturePath, publicKey).then(isValid => {
console.log(`File: ${filePath}`);
console.log(`Signature: ${signaturePath}`);
console.log(`Verification result: ${isValid ? 'Valid signature' : 'Invalid signature'}`);
// Demonstrate a tampered file if (isValid) {
const tamperedFilePath = `${filePath}.tampered`;
fs.copyFileSync(filePath, tamperedFilePath);
// Make a small change to the file const content = fs.readFileSync(tamperedFilePath, 'utf8');
fs.writeFileSync(tamperedFilePath, content.replace('verification', 'TAMPERED'));
// Verify the tampered file with the original signature return verifyFile(tamperedFilePath, signaturePath, publicKey).then(isTamperedValid => {
console.log(`\nTampered file: ${tamperedFilePath}`);
console.log(`Verification result: ${isTamperedValid ? 'Valid signature (unexpected!)' : 'Invalid signature (expected)'}`);
});
}
}).catch(error => {
console.error('Error verifying file:', error.message);
});

Verifying with Different Key Types

The Verify class can work with different formats of public keys:

const crypto = require('crypto');
const fs = require('fs');
// Message to sign and verify const message = 'Message to verify with different key formats';
// Function to sign and verify with different key formats function verifyWithKeyFormat(publicKey, keyFormat, algorithm = 'SHA256') {
try {
// Generate keypair for test const { privateKey, publicKey: generatedPublicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048, publicKeyEncoding: {
type: 'spki', format: 'pem'
}, privateKeyEncoding: {
type: 'pkcs8', format: 'pem'
}
});
// Sign the message with private key const sign = crypto.createSign(algorithm);
sign.update(message);
const signature = sign.sign(privateKey, 'hex');
// Verify with the provided public key format const verify = crypto.createVerify(algorithm);
verify.update(message);
return {
format: keyFormat, isValid: verify.verify(publicKey, signature, 'hex')
};
} catch (error) {
return {

format: keyFormat, error: error.message

};
}
}
// Generate an RSA key pair const { privateKey, publicKey: pemPublicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048, publicKeyEncoding: {
type: 'spki', format: 'pem'
}, privateKeyEncoding: {
type: 'pkcs8', format: 'pem'
}
});
// Sign the message for verification tests const sign = crypto.createSign('SHA256');
sign.update(message);
const signature = sign.sign(privateKey, 'hex');
// Function to verify with different key formats function testVerifyWithKey(publicKey, keyFormat) {
try {
const verify = crypto.createVerify('SHA256');
verify.update(message);
return {
format: keyFormat, isValid: verify.verify(publicKey, signature, 'hex')
};
} catch (error) {
return {

format: keyFormat, error: error.message

};
}
}
console.log(`Message: "${message}"`);
console.log('Signature:', signature.substring(0, 32) + '...');
// 1. Verify with PEM-encoded public key (string)
console.log('\n1. PEM-encoded public key (string):');
console.log(testVerifyWithKey(pemPublicKey, 'PEM string'));
// 2. Verify with PEM-encoded public key (buffer)
console.log('\n2. PEM-encoded public key (buffer):');
console.log(testVerifyWithKey(Buffer.from(pemPublicKey), 'PEM buffer'));
// 3. Verify with KeyObject console.log('\n3. KeyObject:');
const keyObject = crypto.createPublicKey(pemPublicKey);
console.log(testVerifyWithKey(keyObject, 'KeyObject'));
// 4. Try to verify with X.509 certificate console.log('\n4. X.509 Certificate (simulated):');
console.log({
format: 'X.509 Certificate', note: 'In a real scenario, you would load an X.509 certificate containing the public key'
});
// 5. Try to verify with JWK (requires conversion)
console.log('\n5. JWK (requires conversion):');
console.log({
format: 'JWK', note: 'JWK needs to be converted to PEM or KeyObject first'
});

Verifying with Advanced Options

Verifying signatures with specific OpenSSL options:

const crypto = require('crypto');
// Generate RSA key pair const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048, publicKeyEncoding: {
type: 'spki', format: 'pem'
}, privateKeyEncoding: {
type: 'pkcs8', format: 'pem'
}
});
// Message to sign const message = 'Message to verify with different options';
// Function to sign with specific options function signWithOptions(algorithm, message, privateKey, options = {}) {
// Create private key with options const keyWithOptions = {

key: privateKey,...options

};
// Sign the message const sign = crypto.createSign(algorithm);
sign.update(message);
return sign.sign(keyWithOptions, 'hex');
}
// Function to verify with specific options function verifyWithOptions(algorithm, message, publicKey, signature, options = {}) {
try {
// Create public key with options const keyWithOptions = {

key: publicKey,...options

};
// Verify the signature const verify = crypto.createVerify(algorithm);
verify.update(message);
return verify.verify(keyWithOptions, signature, 'hex');
} catch (error) {
return `Error: ${error.message}`;
}
}
console.log(`Message: "${message}"`);
// 1. Sign and verify with standard PKCS#1 v1.5 padding (default)
const sig1 = signWithOptions('SHA256', message, privateKey);
console.log('\n1. Standard PKCS#1 v1.5 padding:');
console.log('Signature:', sig1.substring(0, 32) + '...');
console.log('Verification result:', verifyWithOptions('SHA256', message, publicKey, sig1));
// 2. Sign and verify with PSS padding const pssOptions = {

padding: crypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 32

};
const sig2 = signWithOptions('SHA256', message, privateKey, pssOptions);
console.log('\n2. PSS padding:');
console.log('Signature:', sig2.substring(0, 32) + '...');
console.log('Verification result (matching options):', verifyWithOptions('SHA256', message, publicKey, sig2, pssOptions));
console.log('Verification result (default options):', verifyWithOptions('SHA256', message, publicKey, sig2));
// 3. Verify with PSS padding and different salt lengths console.log('\n3. PSS padding with different salt lengths:');
[20, 32, 48].forEach(saltLength => {
const sigSalt = signWithOptions('SHA256', message, privateKey, {

padding: crypto.constants.RSA_PKCS1_PSS_PADDING, saltLength

});
console.log(`Salt length ${saltLength}:`);
// Try to verify with correct salt length console.log(`  - Verify with correct salt length (${saltLength}):`, verifyWithOptions('SHA256', message, publicKey, sigSalt, {

padding: crypto.constants.RSA_PKCS1_PSS_PADDING, saltLength

}));
// Try to verify with wrong salt length const wrongSaltLength = saltLength + 10;
console.log(`  - Verify with wrong salt length (${wrongSaltLength}):`, verifyWithOptions('SHA256', message, publicKey, sigSalt, {

padding: crypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: wrongSaltLength

}));
});

Certificate-Based Verification

Verifying signatures using X.509 certificates:

const crypto = require('crypto');
const fs = require('fs');
// Function to simulate a certificate-based verification function demonstrateCertificateVerification() {
console.log('Certificate-Based Verification Demonstration');
console.log('-------------------------------------------');
console.log('In a real application, you would:');
console.log('1. Obtain an X.509 certificate containing the signer\'s public key');
console.log('2. Verify the certificate\'s trust chain');
console.log('3. Extract the public key from the certificate');
console.log('4. Use that public key to verify the signature');
console.log('\nSimplified example:');
// Generate a key pair const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048, publicKeyEncoding: {
type: 'spki', format: 'pem'
}, privateKeyEncoding: {
type: 'pkcs8', format: 'pem'
}
});
// In a real app, you'd have a certificate with the public key const mockCertificate = `-----BEGIN CERTIFICATE-----
(This would be a real X.509 certificate containing the public key)
-----END CERTIFICATE-----`;
// Message to sign const message = 'Message signed with a certificate-backed key';
// Sign the message const sign = crypto.createSign('SHA256');
sign.update(message);
const signature = sign.sign(privateKey, 'hex');
console.log(`Message: "${message}"`);
console.log(`Signature: ${signature.substring(0, 32)}...`);
console.log('\nVerification steps:');
console.log('1. Extract public key from certificate (simulated)');
// In a real scenario, you'd extract the public key from the certificate
// For this example, we'll use our generated public key directly console.log('2. Verify the signature using the extracted public key');
const verify = crypto.createVerify('SHA256');
verify.update(message);
const isValid = verify.verify(publicKey, signature, 'hex');
console.log(`Verification result: ${isValid ? 'Valid signature' : 'Invalid signature'}`);
}
// Run the demonstration demonstrateCertificateVerification();

Security Best Practices

When verifying digital signatures, consider these security best practices:

Trust management

: Validate the source of the public key used for verification. Don't trust a public key unless it comes from a trusted source.

Certificate validation

: When using certificates, verify the entire certificate chain and check certificate revocation status.

Matching signing algorithm

: Ensure the verification algorithm matches the signing algorithm, including any options like padding or salt length.

Input validation

: Validate and sanitize any data before verification to prevent injection attacks.

Fail securely

: Always default to rejecting signatures that fail verification for any reason.

Keep verification code simple

: Complexity increases the risk of verification bypass vulnerabilities.

Consider timing attacks

: Signature verification may be vulnerable to timing attacks in some implementations.

Common Use Cases for Signature Verification

Software Updates

: Verifying the authenticity of updates before installation.

Document Verification

: Ensuring digitally signed documents haven't been modified.

API Authentication

: Verifying the identity of API requests.

JWT Validation

: Verifying JSON Web Token signatures.

Previous

Node.js Sign Reference

Next

Node.js Socket Reference