-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
dbea5b7
commit a03cfe7
Showing
5 changed files
with
247 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,162 @@ | ||
// | ||
import crypto from 'crypto' | ||
import Hmac from '@alessiofrittoli/crypto-key/Hmac' | ||
import Algorithm from '@alessiofrittoli/crypto-algorithm' | ||
import type Sign from './types' | ||
|
||
|
||
class Signature | ||
{ | ||
private static Algorithm: Sign.AlgorithmJwkName = 'HS256' | ||
private static HashDigest: Sign.Hash = 'SHA-256' | ||
|
||
|
||
/** | ||
* Sincronously create a signature with the given data. | ||
* | ||
* @param data The data to sign. | ||
* @param key The private key used for HMAC or the PEM private key for RSA, ECDSA and RSASSA-PSS signing algorithms. | ||
* @param algorithm ( Optional ) The Jwk Algorithm name to use. Default: `HS256`. | ||
* @returns The signature Buffer. Throws a new Exception on failure. | ||
*/ | ||
static sign( | ||
data : crypto.BinaryLike, | ||
key : Sign.PrivateKey, | ||
algorithm : Sign.AlgorithmJwkName = Signature.Algorithm, | ||
): Buffer | ||
{ | ||
if ( ! data ) { | ||
throw new Error( 'No data to sign has been provided.' ) | ||
} | ||
if ( ! key ) { | ||
throw new Error( 'No Private Key has been provided.' ) | ||
} | ||
|
||
const digest = Signature.jwkAlgToHash( algorithm ) || Signature.HashDigest | ||
|
||
/** HMAC SHA signing algorithm */ | ||
if ( algorithm.startsWith( 'HS' ) ) { | ||
|
||
let secret = key as Sign.PrivateKey<'HMAC'> | ||
secret = secret instanceof CryptoKey ? crypto.KeyObject.from( secret ) : secret | ||
|
||
return ( | ||
Hmac.digest( data, secret, digest ) | ||
) | ||
} | ||
|
||
|
||
if ( algorithm === 'EdDSA' ) { | ||
|
||
let secret = key as Sign.PrivateKey<'EdDSA'> | ||
secret = secret instanceof CryptoKey ? crypto.KeyObject.from( secret ) : secret | ||
const _data = typeof data !== 'string' ? data : Buffer.from( data ) | ||
|
||
return crypto.sign( null, _data, secret ) | ||
|
||
} | ||
|
||
|
||
/** RSASSA/RSASSA-PSS/ECDSA/DSA SHA signing algorithm */ | ||
let secret = key as Sign.PrivateKey<'RSA-PSS' | 'RSASSA-PKCS1-v1_5' | 'ECDSA' | 'DSA'> | ||
secret = secret instanceof CryptoKey ? crypto.KeyObject.from( secret ) : secret | ||
const Sign = crypto.createSign( digest ) | ||
|
||
Sign.write( data ) | ||
Sign.end() | ||
|
||
return Sign.sign( secret ) | ||
|
||
} | ||
|
||
|
||
/** | ||
* Sincronously verify a signature. | ||
* | ||
* @param signature The signature buffer. | ||
* @param data The signed data. | ||
* @param key The public key used for HMAC, or RSA, ECDSA and RSASSA-PSS signing verifications. | ||
* @param algorithm ( Optional ) The Jwk Algorithm name to use. Default: `HS256`. | ||
* @returns `true` if signature is valid. Throws a new Exception on failure. | ||
*/ | ||
static isValid( | ||
signature : Buffer, | ||
data : crypto.BinaryLike, | ||
key : Sign.PublicKey, | ||
algorithm : Sign.AlgorithmJwkName = Signature.Algorithm, | ||
): true | ||
{ | ||
if ( ! signature ) { | ||
throw new Error( 'No signature provided.' ) | ||
} | ||
if ( ! data ) { | ||
throw new Error( 'The signed data is needed for integrity controls.' ) | ||
} | ||
if ( ! key ) { | ||
throw new Error( 'No Private Key has been provided.' ) | ||
} | ||
|
||
const digest = Signature.jwkAlgToHash( algorithm ) || Signature.HashDigest | ||
|
||
/** HMAC SHA signing algorithm */ | ||
if ( algorithm.startsWith( 'HS' ) ) { | ||
|
||
let secret = key as Sign.PublicKey<'HMAC'> | ||
secret = secret instanceof CryptoKey ? crypto.KeyObject.from( secret ) : secret | ||
const isValid = Hmac.isValid( signature, data, secret, digest ) | ||
|
||
if ( ! isValid ) { | ||
throw new Error( 'Invalid signature.' ) | ||
} | ||
|
||
return true | ||
|
||
} | ||
|
||
if ( algorithm === 'EdDSA' ) { | ||
|
||
let secret = key as Sign.PublicKey<'EdDSA'> | ||
secret = secret instanceof CryptoKey ? crypto.KeyObject.from( secret ) : secret | ||
const _data = typeof data !== 'string' ? data : Buffer.from( data ) | ||
const isValid = crypto.verify( null, _data, secret, signature ) | ||
|
||
if ( ! isValid ) { | ||
throw new Error( 'Invalid signature.' ) | ||
} | ||
|
||
return true | ||
|
||
} | ||
|
||
/** RSASSA/RSASSA-PSS/ECDSA/DSA SHA signing algorithm */ | ||
let secret = key as Sign.PublicKey<'RSA-PSS' | 'RSASSA-PKCS1-v1_5' | 'ECDSA' | 'DSA'> | ||
secret = secret instanceof CryptoKey ? crypto.KeyObject.from( secret ) : secret | ||
const Verify = crypto.createVerify( digest ) | ||
|
||
Verify.write( data ) | ||
Verify.end() | ||
|
||
const isValid = Verify.verify( secret, signature ) | ||
|
||
if ( ! isValid ) { | ||
throw new Error( 'Invalid signature.' ) | ||
} | ||
|
||
return true | ||
|
||
} | ||
|
||
|
||
/** | ||
* Get the Algorithm digest hash name. | ||
* | ||
* @param jwkAlg The Algorithm. | ||
* @returns The corresponding Algorithm digest hash name. | ||
*/ | ||
private static jwkAlgToHash( jwkAlg: Sign.AlgorithmJwkName ) | ||
{ | ||
return Algorithm.by( { jwkAlg } )?.hash | ||
} | ||
} | ||
|
||
|
||
export default Signature |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import type crypto from 'crypto' | ||
import type Algo from '@alessiofrittoli/crypto-algorithm/types' | ||
|
||
namespace Sign | ||
{ | ||
/** | ||
* Signature algorithm parameter. | ||
* | ||
* @link https://datatracker.ietf.org/doc/html/rfc7518#section-3.1 | ||
*/ | ||
export type AlgorithmJwkName = Algo.JwkName | ||
export type Hash = Algo.Hash | ||
|
||
/** | ||
* The private key used for HMAC or the PEM private key for RSA, ECDSA and RSASSA-PSS signing algorithms. | ||
* | ||
*/ | ||
export type PrivateKey< | ||
TAlg extends Algo.Name = Algo.Name | ||
> = ( | ||
TAlg extends `HMAC` ? ( crypto.BinaryLike | crypto.KeyObject | CryptoKey ) | ||
: ( crypto.KeyLike | crypto.SignKeyObjectInput | crypto.SignPrivateKeyInput | CryptoKey ) | ||
) | ||
|
||
|
||
/** | ||
* The public key used for HMAC, or RSA, ECDSA and RSASSA-PSS signing verifications. | ||
* | ||
*/ | ||
export type PublicKey< | ||
TAlg extends Algo.Name = Algo.Name | ||
> = ( | ||
TAlg extends `HMAC` ? ( crypto.BinaryLike | crypto.KeyObject | CryptoKey ) | ||
: ( crypto.KeyLike | crypto.VerifyKeyObjectInput | crypto.VerifyPublicKeyInput | crypto.VerifyJsonWebKeyInput | CryptoKey ) | ||
) | ||
} | ||
|
||
|
||
export default Sign |