or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

asymmetric-cryptography.mddigital-signatures.mdhash-functions.mdhmac.mdindex.mdkey-derivation.mdkey-exchange.mdrandom-generation.mdsymmetric-encryption.md
tile.json

digital-signatures.mddocs/

Digital Signatures

RSA and ECDSA digital signatures for authentication, integrity verification, and non-repudiation using public/private key cryptography.

Capabilities

Create Sign Object

Creates a sign object for generating digital signatures.

/**
 * Create a sign object for the specified algorithm
 * @param {string} algorithm - Signature algorithm (e.g., 'RSA-SHA256', 'sha256', 'RSA-SHA1')
 * @returns {Sign} Sign object for creating signatures
 */
function createSign(algorithm) { }

/**
 * Sign object for creating digital signatures
 * @class Sign
 */
/**
 * Update the sign object with data to be signed
 * @param {string|Buffer} data - Data to sign (string or Buffer)
 * @returns {Sign} Sign object for method chaining
 */
Sign.prototype.update = function(data) { };

/**
 * Generate the digital signature
 * @param {string|Buffer|Object} privateKey - Private key as string, Buffer, or key object
 * @param {string} [outputFormat] - Output format ('hex', 'base64', 'latin1', etc.)
 * @returns {Buffer|string} Digital signature as Buffer or encoded string
 */
Sign.prototype.sign = function(privateKey, outputFormat) { };

Create Verify Object

Creates a verify object for verifying digital signatures.

/**
 * Create a verify object for the specified algorithm
 * @param {string} algorithm - Signature algorithm (e.g., 'RSA-SHA256', 'sha256', 'RSA-SHA1')
 * @returns {Verify} Verify object for verifying signatures
 */
function createVerify(algorithm) { }

/**
 * Verify object for verifying digital signatures
 * @class Verify
 */
/**
 * Update the verify object with data that was signed
 * @param {string|Buffer} data - Original data that was signed (string or Buffer)
 * @returns {Verify} Verify object for method chaining
 */
Verify.prototype.update = function(data) { };

/**
 * Verify the digital signature
 * @param {string|Buffer|Object} object - Public key or certificate as string, Buffer, or key object
 * @param {Buffer|string} signature - Signature to verify as Buffer or string
 * @param {string} [signatureFormat] - Format of signature if string ('hex', 'base64', etc.)
 * @returns {boolean} True if signature is valid, false otherwise
 */
Verify.prototype.verify = function(object, signature, signatureFormat) { };

Class Constructors

Direct access to Sign and Verify classes.

/**
 * Sign class constructor (equivalent to createSign result)
 * @constructor
 */
function Sign() { }

/**
 * Verify class constructor (equivalent to createVerify result)
 * @constructor
 */
function Verify() { }

Usage Examples

Basic Digital Signatures

Create and verify digital signatures using RSA keys.

const crypto = require('crypto-browserify');

// Example RSA key pair
const privateKey = `-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDX...
-----END PRIVATE KEY-----`;

const publicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1234...
-----END PUBLIC KEY-----`;

// Sign data
function signData(data, privateKey) {
  const sign = crypto.createSign('RSA-SHA256');
  sign.update(data);
  return sign.sign(privateKey, 'base64');
}

// Verify signature
function verifySignature(data, signature, publicKey) {
  const verify = crypto.createVerify('RSA-SHA256');
  verify.update(data);
  return verify.verify(publicKey, signature, 'base64');
}

// Usage
const message = 'This is an important message';
const signature = signData(message, privateKey);
console.log('Signature:', signature);

const isValid = verifySignature(message, signature, publicKey);
console.log('Signature valid:', isValid); // true

// Test with tampered data
const tamperedMessage = 'This is a tampered message';
const isValidTampered = verifySignature(tamperedMessage, signature, publicKey);
console.log('Tampered signature valid:', isValidTampered); // false

Document Signing

Sign documents or files for integrity verification.

const crypto = require('crypto-browserify');
const fs = require('fs');

class DocumentSigner {
  constructor(privateKey, publicKey) {
    this.privateKey = privateKey;
    this.publicKey = publicKey;
  }
  
  signDocument(filePath) {
    const data = fs.readFileSync(filePath);
    const sign = crypto.createSign('RSA-SHA256');
    sign.update(data);
    
    const signature = sign.sign(this.privateKey, 'base64');
    
    return {
      file: filePath,
      signature: signature,
      algorithm: 'RSA-SHA256',
      timestamp: new Date().toISOString()
    };
  }
  
  verifyDocument(filePath, signatureInfo) {
    try {
      const data = fs.readFileSync(filePath);
      const verify = crypto.createVerify(signatureInfo.algorithm);
      verify.update(data);
      
      return verify.verify(this.publicKey, signatureInfo.signature, 'base64');
    } catch (err) {
      console.error('Document verification failed:', err.message);
      return false;
    }
  }
}

// Usage
const signer = new DocumentSigner(privateKey, publicKey);

// Sign document
const signatureInfo = signer.signDocument('important-document.pdf');
console.log('Document signed:', signatureInfo);

// Verify document
const isValid = signer.verifyDocument('important-document.pdf', signatureInfo);
console.log('Document signature valid:', isValid);

JSON Web Token (JWT) Signing

Sign JWT tokens for authentication.

const crypto = require('crypto-browserify');

function createJWT(payload, privateKey, algorithm = 'RS256') {
  // JWT header
  const header = {
    alg: algorithm,
    typ: 'JWT'
  };
  
  // Encode header and payload
  const encodedHeader = Buffer.from(JSON.stringify(header)).toString('base64url');
  const encodedPayload = Buffer.from(JSON.stringify(payload)).toString('base64url');
  
  // Create signature
  const data = `${encodedHeader}.${encodedPayload}`;
  const sign = crypto.createSign('RSA-SHA256');
  sign.update(data);
  const signature = sign.sign(privateKey, 'base64')
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=/g, '');
  
  return `${data}.${signature}`;
}

function verifyJWT(token, publicKey) {
  const parts = token.split('.');
  if (parts.length !== 3) return false;
  
  const [encodedHeader, encodedPayload, signature] = parts;
  const data = `${encodedHeader}.${encodedPayload}`;
  
  // Convert base64url signature back to base64
  const base64Signature = signature
    .replace(/-/g, '+')
    .replace(/_/g, '/') + '==';
  
  const verify = crypto.createVerify('RSA-SHA256');
  verify.update(data);
  
  return verify.verify(publicKey, base64Signature, 'base64');
}

// Usage
const payload = {
  userId: 12345,
  username: 'alice',
  exp: Math.floor(Date.now() / 1000) + 3600 // 1 hour expiration
};

const jwt = createJWT(payload, privateKey);
console.log('JWT:', jwt);

const isValidJWT = verifyJWT(jwt, publicKey);
console.log('JWT valid:', isValidJWT);

Multi-part Data Signing

Sign data that comes in multiple chunks or streams.

const crypto = require('crypto-browserify');

function createIncrementalSigner(algorithm, privateKey) {
  const sign = crypto.createSign(algorithm);
  
  return {
    update: (data) => sign.update(data),
    finalize: (outputFormat = 'base64') => sign.sign(privateKey, outputFormat)
  };
}

function createIncrementalVerifier(algorithm, publicKey) {
  const verify = crypto.createVerify(algorithm);
  
  return {
    update: (data) => verify.update(data),
    verify: (signature, signatureFormat = 'base64') => 
      verify.verify(publicKey, signature, signatureFormat)
  };
}

// Usage for streaming data
const signer = createIncrementalSigner('RSA-SHA256', privateKey);

// Add data in chunks
signer.update('First chunk of data');
signer.update('Second chunk of data');
signer.update('Final chunk of data');

// Generate signature
const signature = signer.finalize();
console.log('Incremental signature:', signature);

// Verify with same chunks
const verifier = createIncrementalVerifier('RSA-SHA256', publicKey);
verifier.update('First chunk of data');
verifier.update('Second chunk of data');
verifier.update('Final chunk of data');

const isValid = verifier.verify(signature);
console.log('Incremental signature valid:', isValid);

Code Signing

Sign code or software packages for authenticity verification.

const crypto = require('crypto-browserify');

class CodeSigner {
  constructor(privateKey, certificate) {
    this.privateKey = privateKey;
    this.certificate = certificate;
  }
  
  signCode(codeBuffer, metadata = {}) {
    // Create hash of the code
    const hash = crypto.createHash('sha256');
    hash.update(codeBuffer);
    const codeHash = hash.digest('hex');
    
    // Create signature payload
    const signaturePayload = {
      codeHash: codeHash,
      size: codeBuffer.length,
      timestamp: new Date().toISOString(),
      ...metadata
    };
    
    // Sign the payload
    const sign = crypto.createSign('RSA-SHA256');
    sign.update(JSON.stringify(signaturePayload));
    const signature = sign.sign(this.privateKey, 'base64');
    
    return {
      payload: signaturePayload,
      signature: signature,
      certificate: this.certificate
    };
  }
  
  verifyCode(codeBuffer, signatureInfo) {
    try {
      // Verify code hash
      const hash = crypto.createHash('sha256');
      hash.update(codeBuffer);
      const codeHash = hash.digest('hex');
      
      if (codeHash !== signatureInfo.payload.codeHash) {
        return { valid: false, reason: 'Code hash mismatch' };
      }
      
      // Verify signature
      const verify = crypto.createVerify('RSA-SHA256');
      verify.update(JSON.stringify(signatureInfo.payload));
      const isValid = verify.verify(signatureInfo.certificate, signatureInfo.signature, 'base64');
      
      return { 
        valid: isValid, 
        reason: isValid ? 'Valid signature' : 'Invalid signature',
        metadata: signatureInfo.payload
      };
    } catch (err) {
      return { valid: false, reason: err.message };
    }
  }
}

// Usage
const codeSigner = new CodeSigner(privateKey, publicKey);

// Sign some code
const codeToSign = Buffer.from(`
function hello() {
  console.log("Hello, world!");
}
`);

const codeSignature = codeSigner.signCode(codeToSign, {
  version: '1.0.0',
  author: 'Developer Name'
});

console.log('Code signature:', codeSignature);

// Verify code
const verification = codeSigner.verifyCode(codeToSign, codeSignature);
console.log('Code verification:', verification);

Supported Algorithms

Common signature algorithms:

RSA-based Algorithms

  • 'RSA-SHA1' - RSA with SHA-1 (deprecated)
  • 'RSA-SHA256' - RSA with SHA-256 (recommended)
  • 'RSA-SHA384' - RSA with SHA-384
  • 'RSA-SHA512' - RSA with SHA-512

Legacy Algorithm Names

  • 'sha1' - Equivalent to RSA-SHA1
  • 'sha256' - Equivalent to RSA-SHA256
  • 'sha384' - Equivalent to RSA-SHA384
  • 'sha512' - Equivalent to RSA-SHA512

ECDSA (via browserify-sign)

  • Additional ECDSA algorithms may be available

Security Best Practices

Algorithm Selection

  • Use SHA-256 or higher (avoid SHA-1)
  • Prefer explicit algorithm names (e.g., 'RSA-SHA256' over 'sha256')

Key Management

  • Use at least 2048-bit RSA keys (4096-bit preferred)
  • Protect private keys with strong passphrases
  • Store keys securely and limit access

Signature Verification

  • Always verify signatures before trusting data
  • Check certificate validity and expiration
  • Implement proper error handling

Timestamp Security

  • Include timestamps in signed data to prevent replay attacks
  • Consider using trusted timestamp services for critical applications

Error Handling

Digital signature functions may throw errors in the following scenarios:

  • Unsupported algorithm: When the signature algorithm is not available
  • Invalid key format: Malformed keys or certificates
  • Sign after sign: Calling sign() multiple times on the same object
  • Verify without data: Calling verify() without updating with data first
const crypto = require('crypto-browserify');

try {
  const sign = crypto.createSign('unsupported-algorithm');
} catch (err) {
  console.error('Unsupported algorithm:', err.message);
}

try {
  const sign = crypto.createSign('RSA-SHA256');
  sign.update('data');
  const signature1 = sign.sign(privateKey, 'base64');
  const signature2 = sign.sign(privateKey, 'base64'); // This will throw
} catch (err) {
  console.error('Cannot reuse sign object:', err.message);
}

// Proper error handling for verification
function safeVerify(data, signature, publicKey) {
  try {
    const verify = crypto.createVerify('RSA-SHA256');
    verify.update(data);
    return verify.verify(publicKey, signature, 'base64');
  } catch (err) {
    console.error('Signature verification failed:', err.message);
    return false;
  }
}