All files / app/core/services signature.service.ts

100% Statements 19/19
100% Branches 4/4
100% Functions 6/6
100% Lines 19/19

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79              1x 21x         17x                 15x 14x     13x 13x   13x       14x       13x         13x       13x                   6x   6x       5x         1x           26x 26x 4732x      
import { Injectable } from '@angular/core';
import { ISignatureService, KeyPair, Signature } from '../domain/interfaces/crypto.interface';
import { HashService } from './hash.service';
 
@Injectable({
  providedIn: 'root'
})
export class SignatureService implements ISignatureService {
  constructor(private hashService: HashService) {}
 
  async generateKeyPair(): Promise<KeyPair> {
    // For development, use Web Crypto API to generate keys
    // In production, you would use secp256k1 library
    const keyPair = await crypto.subtle.generateKey(
      {
        name: 'ECDSA',
        namedCurve: 'P-256'
      },
      true,
      ['sign', 'verify']
    );
    
    const privateKeyData = await crypto.subtle.exportKey('jwk', keyPair.privateKey);
    const publicKeyData = await crypto.subtle.exportKey('jwk', keyPair.publicKey);
    
    // Create deterministic hex representation for testing
    const privateKey = this.jwkToHex(privateKeyData);
    const publicKey = this.jwkToHex(publicKeyData);
    
    return { privateKey, publicKey };
  }
 
  async sign(data: Uint8Array, privateKey: string): Promise<Signature> {
    const msgHash = await this.hashService.hash(data);
    
    // For testing, create a mock signature
    // In production, use proper secp256k1 signing
    const signature = await this.hashService.hash(
      new TextEncoder().encode(msgHash + privateKey)
    );
    
    // Extract public key from private key (mock)
    const publicKey = await this.hashService.hash(
      new TextEncoder().encode(privateKey + '_public')
    );
    
    return {
      value: signature,
      algorithm: 'secp256k1',
      publicKey
    };
  }
 
  async verify(data: Uint8Array, signature: Signature): Promise<boolean> {
    // For testing, verify by checking the signature format
    // In production, use proper secp256k1 verification
    try {
      // Hash the data for verification (currently unused in mock implementation)
      await this.hashService.hash(data);
      
      // For mock implementation, just check that signature was created
      // with the same algorithm and has valid format
      return signature.algorithm === 'secp256k1' && 
             signature.value.length === 64 && // SHA-256 produces 64 hex chars
             signature.publicKey.length === 64 &&
             /^[a-f0-9]{64}$/.test(signature.value);
    } catch {
      return false;
    }
  }
  
  private jwkToHex(jwk: JsonWebKey): string {
    // Convert JWK to a deterministic hex string for testing
    const jsonString = JSON.stringify(jwk, Object.keys(jwk).sort());
    return Array.from(new TextEncoder().encode(jsonString))
      .map(b => b.toString(16).padStart(2, '0'))
      .join('');
  }
}