CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sodium-native

Low level bindings for libsodium cryptographic library

Pending
Overview
Eval results
Files

auth.mddocs/

Message Authentication

Message authentication codes (MAC) using HMAC-SHA512 and Poly1305 for data integrity verification and authenticity.

Capabilities

HMAC-SHA512 Authentication

Compute and verify HMAC-SHA512 message authentication codes.

/**
 * Compute HMAC-SHA512 authentication tag
 * @param out - Output buffer for authentication tag (must be BYTES long)
 * @param input - Input buffer to authenticate
 * @param k - Key buffer (must be KEYBYTES long)
 * @throws Error if buffer sizes are incorrect or authentication fails
 */
function crypto_auth(out: Buffer, input: Buffer, k: Buffer): void;

/**
 * Verify HMAC-SHA512 authentication tag
 * @param h - Authentication tag to verify (must be BYTES long)
 * @param input - Input buffer that was authenticated
 * @param k - Key buffer (must be KEYBYTES long)
 * @returns true if tag is valid, false otherwise
 */
function crypto_auth_verify(h: Buffer, input: Buffer, k: Buffer): boolean;

Usage Example:

const sodium = require('sodium-native');

// Generate authentication key
const key = Buffer.alloc(sodium.crypto_auth_KEYBYTES);
sodium.randombytes_buf(key);

// Authenticate a message
const message = Buffer.from('Important message');
const tag = Buffer.alloc(sodium.crypto_auth_BYTES);
sodium.crypto_auth(tag, message, key);

// Verify the authentication tag
if (sodium.crypto_auth_verify(tag, message, key)) {
  console.log('Message is authentic');
} else {
  console.log('Message authentication failed');
}

Poly1305 One-time Authentication

Poly1305 MAC for high-performance message authentication with one-time keys.

/**
 * Compute Poly1305 authentication tag
 * @param out - Output buffer for authentication tag (must be BYTES long)
 * @param input - Input buffer to authenticate
 * @param k - One-time key buffer (must be KEYBYTES long)
 * @throws Error if buffer sizes are incorrect or authentication fails
 */
function crypto_onetimeauth(out: Buffer, input: Buffer, k: Buffer): void;

/**
 * Verify Poly1305 authentication tag
 * @param h - Authentication tag to verify (must be BYTES long)
 * @param input - Input buffer that was authenticated
 * @param k - One-time key buffer (must be KEYBYTES long)
 * @returns true if tag is valid, false otherwise
 */
function crypto_onetimeauth_verify(h: Buffer, input: Buffer, k: Buffer): boolean;

Poly1305 Streaming Authentication

Initialize, update, and finalize Poly1305 authentication for large data.

/**
 * Initialize Poly1305 streaming authentication
 * @param state - State buffer (must be STATEBYTES long)
 * @param k - One-time key buffer (must be KEYBYTES long)
 * @throws Error if initialization fails or buffer sizes incorrect
 */
function crypto_onetimeauth_init(state: Buffer, k: Buffer): void;

/**
 * Update Poly1305 streaming authentication with more data
 * @param state - State buffer from init
 * @param input - Input buffer to add to authentication
 * @throws Error if update fails
 */
function crypto_onetimeauth_update(state: Buffer, input: Buffer): void;

/**
 * Finalize Poly1305 streaming authentication and get tag
 * @param state - State buffer from init/update
 * @param out - Output buffer for authentication tag (must be BYTES long)
 * @throws Error if finalization fails
 */
function crypto_onetimeauth_final(state: Buffer, out: Buffer): void;

Usage Example:

const sodium = require('sodium-native');

// Generate one-time key
const key = Buffer.alloc(sodium.crypto_onetimeauth_KEYBYTES);
sodium.randombytes_buf(key);

// Streaming authentication for large data
const state = Buffer.alloc(sodium.crypto_onetimeauth_STATEBYTES);
sodium.crypto_onetimeauth_init(state, key);

// Process data in chunks
const chunk1 = Buffer.from('First part of ');
const chunk2 = Buffer.from('large message');

sodium.crypto_onetimeauth_update(state, chunk1);
sodium.crypto_onetimeauth_update(state, chunk2);

const tag = Buffer.alloc(sodium.crypto_onetimeauth_BYTES);
sodium.crypto_onetimeauth_final(state, tag);

// Verify using one-shot function
const fullMessage = Buffer.concat([chunk1, chunk2]);
if (sodium.crypto_onetimeauth_verify(tag, fullMessage, key)) {
  console.log('Message is authentic');
}

Constants

// HMAC-SHA512 constants
const crypto_auth_BYTES: number;
const crypto_auth_KEYBYTES: number;

// Poly1305 constants
const crypto_onetimeauth_STATEBYTES: number;
const crypto_onetimeauth_BYTES: number;
const crypto_onetimeauth_KEYBYTES: number;

Security Considerations

  • Key Reuse: HMAC keys can be reused safely, but Poly1305 keys must be used only once.
  • Key Generation: Use cryptographically secure random key generation.
  • Timing Attacks: Both implementations use constant-time comparison for verification.
  • Key Management: Store authentication keys securely and separately from data.

Common Patterns

Message Integrity Service

const sodium = require('sodium-native');

class MessageIntegrity {
  constructor() {
    this.hmacKey = Buffer.alloc(sodium.crypto_auth_KEYBYTES);
    sodium.randombytes_buf(this.hmacKey);
  }
  
  sign(message) {
    const tag = Buffer.alloc(sodium.crypto_auth_BYTES);
    sodium.crypto_auth(tag, message, this.hmacKey);
    
    return {
      message: message,
      tag: tag
    };
  }
  
  verify(signedMessage) {
    return sodium.crypto_auth_verify(
      signedMessage.tag,
      signedMessage.message,
      this.hmacKey
    );
  }
  
  // For one-time use (e.g., network packets)
  signOneTime(message, oneTimeKey) {
    const tag = Buffer.alloc(sodium.crypto_onetimeauth_BYTES);
    sodium.crypto_onetimeauth(tag, message, oneTimeKey);
    return tag;
  }
  
  verifyOneTime(message, tag, oneTimeKey) {
    return sodium.crypto_onetimeauth_verify(tag, message, oneTimeKey);
  }
}

File Integrity Checker

const sodium = require('sodium-native');
const fs = require('fs');

class FileIntegrityChecker {
  constructor(keyFile) {
    if (fs.existsSync(keyFile)) {
      this.key = fs.readFileSync(keyFile);
    } else {
      this.key = Buffer.alloc(sodium.crypto_auth_KEYBYTES);
      sodium.randombytes_buf(this.key);
      fs.writeFileSync(keyFile, this.key);
    }
  }
  
  createChecksum(filename) {
    const data = fs.readFileSync(filename);
    const checksum = Buffer.alloc(sodium.crypto_auth_BYTES);
    sodium.crypto_auth(checksum, data, this.key);
    
    // Save checksum file
    fs.writeFileSync(`${filename}.checksum`, checksum);
    return checksum;
  }
  
  verifyChecksum(filename) {
    const checksumFile = `${filename}.checksum`;
    if (!fs.existsSync(checksumFile)) {
      throw new Error('Checksum file not found');
    }
    
    const data = fs.readFileSync(filename);
    const storedChecksum = fs.readFileSync(checksumFile);
    
    return sodium.crypto_auth_verify(storedChecksum, data, this.key);
  }
  
  // For streaming large files
  createStreamingChecksum(filename) {
    const state = Buffer.alloc(sodium.crypto_auth_STATEBYTES);
    sodium.crypto_auth_init(state, this.key);
    
    const fileStream = fs.createReadStream(filename, { highWaterMark: 64 * 1024 });
    
    return new Promise((resolve, reject) => {
      fileStream.on('data', (chunk) => {
        sodium.crypto_auth_update(state, chunk);
      });
      
      fileStream.on('end', () => {
        const checksum = Buffer.alloc(sodium.crypto_auth_BYTES);
        sodium.crypto_auth_final(state, checksum);
        resolve(checksum);
      });
      
      fileStream.on('error', reject);
    });
  }
}

API Request Authentication

const sodium = require('sodium-native');

class APIAuth {
  constructor(secretKey) {
    this.secretKey = Buffer.from(secretKey);
    if (this.secretKey.length !== sodium.crypto_auth_KEYBYTES) {
      throw new Error('Invalid secret key length');
    }
  }
  
  signRequest(method, url, body, timestamp) {
    const message = Buffer.from(`${method}|${url}|${body}|${timestamp}`);
    const signature = Buffer.alloc(sodium.crypto_auth_BYTES);
    
    sodium.crypto_auth(signature, message, this.secretKey);
    
    return {
      signature: signature.toString('hex'),
      timestamp: timestamp
    };
  }
  
  verifyRequest(method, url, body, signature, timestamp) {
    const message = Buffer.from(`${method}|${url}|${body}|${timestamp}`);
    const signatureBuffer = Buffer.from(signature, 'hex');
    
    if (signatureBuffer.length !== sodium.crypto_auth_BYTES) {
      return false;
    }
    
    return sodium.crypto_auth_verify(signatureBuffer, message, this.secretKey);
  }
}

// Usage
const apiAuth = new APIAuth('your-secret-key-32-bytes-long!!!!!');
const timestamp = Date.now();
const auth = apiAuth.signRequest('GET', '/api/users', '', timestamp);

console.log('Authorization:', auth.signature);
console.log('Timestamp:', auth.timestamp);

Install with Tessl CLI

npx tessl i tessl/npm-sodium-native

docs

aead.md

auth.md

box.md

ed25519.md

hash.md

index.md

kdf.md

kx.md

memory.md

pwhash.md

random.md

secretbox.md

secretstream.md

shorthash.md

sign.md

stream.md

tile.json