@alessiofrittoli/crypto-cipher
Version:
Node.js Cipher cryptograph utility library
2 lines (1 loc) • 7.12 kB
JavaScript
import i from"crypto";import{extractBytesFromReadable as E}from"@alessiofrittoli/stream-reader/utils";import{clamp as O}from"@alessiofrittoli/math-utils";import{coerceToUint8Array as T,readUint32BE as l,writeUint32BE as m}from"@alessiofrittoli/crypto-buffer";var t=class t{static Encrypt(a,e,s={}){let r=T(a),{salt:n,Key:o,IV:c,AAD:A,options:{algorithm:p,authTag:h}}=t.NewKeyIV({...s,secret:e});if(t.IsCBC(p)){let I=i.createCipheriv(p,o,c),u=Buffer.concat([I.update(r),I.final()]);return Buffer.concat([n,c,u])}let y=i.createCipheriv(p,o,c,{authTagLength:h});(t.IsCCM(p)||t.IsChacha20Poly(p))&&y.setAAD(A,{plaintextLength:r.length}),(t.IsGCM(p)||t.IsOCB(p))&&y.setAAD(A);let C=Buffer.concat([y.update(r),y.final()]),L=y.getAuthTag();return Buffer.concat([n,c,A,L,C])}static Decrypt(a,e,s={}){let r=T(a),n=t.ResolveOptions(s),o=T(e),{algorithm:c}=n,A=r.subarray(0,n.salt);r=r.subarray(n.salt);let p=r.subarray(0,n.iv);r=r.subarray(n.iv);let h=i.scryptSync(o,A,n.length);if(t.IsCBC(c)){let G=i.createDecipheriv(n.algorithm,h,p);return Buffer.concat([G.update(r),G.final()])}let y=n.aadLength,C=n.authTag,L=r.subarray(0,y);r=r.subarray(y);let I=r.subarray(0,C);r=r.subarray(C);let u=i.createDecipheriv(c,h,p,{authTagLength:C});return(t.IsCCM(c)||t.IsChacha20Poly(c))&&u.setAAD(L,{plaintextLength:r.length}),(t.IsGCM(c)||t.IsOCB(c))&&u.setAAD(L),u.setAuthTag(I),Buffer.concat([u.update(r),u.final()])}static HybridEncrypt(a,e,s){let r=i.randomBytes(32),n=i.publicEncrypt({key:e,padding:i.constants.RSA_PKCS1_OAEP_PADDING,oaepHash:"sha256"},r);return Buffer.concat([m(n.length),n,t.Encrypt(a,r,s)])}static HybridDecrypt(a,e,s){let r=Buffer.from(T(a)),n=l(r.subarray(0,4)),o=r.subarray(4,4+n),c=r.subarray(4+n),{privateKey:A,passphrase:p}=t.GetPrivateKey(e),h=i.privateDecrypt({key:A,passphrase:p,padding:i.constants.RSA_PKCS1_OAEP_PADDING,oaepHash:"sha256"},o);return t.Decrypt(c,h,s)}static DecryptKeyIV(a){let{privateKey:e,EncryptedKeyIV:s,keyLength:r}=a,{privateKey:n,passphrase:o}=t.GetPrivateKey(e),c=i.privateDecrypt({key:n,passphrase:o,padding:i.constants.RSA_PKCS1_OAEP_PADDING,oaepHash:"sha256"},s),A=c.subarray(0,r),p=c.subarray(r);return{Key:A,IV:p}}static GetPrivateKey(a){let e=typeof a=="object"&&"key"in a?a.key:a,s=typeof a=="object"&&"passphrase"in a?a.passphrase:void 0;return{privateKey:e,passphrase:s}}static NewKeyIV(a={}){let{secret:e}=a,s=t.ResolveOptions(a),r=e?T(e):i.randomBytes(s.length),n=i.randomBytes(s.salt),o=i.scryptSync(r,n,s.length),c=i.randomBytes(s.iv),A=s.aad||i.scryptSync(o,n,s.aadLength);return{options:s,Key:o,IV:c,AAD:A,salt:n}}static ResolveOptions(a={}){let e={...a};e.aad&&(e.aad=T(e.aad)),e.salt||(e.salt=t.SALT_LENGTH.default),e.authTag||(e.authTag=t.AUTH_TAG_LENGTH.default),e.aadLength=e.aad?.length||e.aadLength||t.AAD_LENGTH.default,e.salt=O(e.salt,t.SALT_LENGTH.min,t.SALT_LENGTH.max),e.authTag=O(e.authTag,t.AUTH_TAG_LENGTH.min,t.AUTH_TAG_LENGTH.max),e.aad||(e.aadLength=O(e.aadLength,t.AAD_LENGTH.min,t.AAD_LENGTH.max));let{keyLength:s,algorithm:r}=t.GetKeyLength(a.algorithm);return e.algorithm=r,e.length=s,e.iv=t.GetIVLength(r,a),e}static GetIVLength(a=t.DEFAULT_ALGORITHM.buffer,e={}){switch(a){case t.ALGORITHM.AES_128_CCM:case t.ALGORITHM.AES_192_CCM:case t.ALGORITHM.AES_256_CCM:case t.ALGORITHM.AES_128_OCB:case t.ALGORITHM.AES_192_OCB:case t.ALGORITHM.AES_256_OCB:return 8;case t.ALGORITHM.CHACHA_20_POLY:return 12;default:return O(e.iv||t.IV_LENGTH.default,t.IV_LENGTH.min,t.IV_LENGTH.max)}}static GetKeyLength(a=t.DEFAULT_ALGORITHM.buffer){switch(a){case t.ALGORITHM.CHACHA_20_POLY:return{algorithm:a,keyLength:256/8};case t.ALGORITHM.AES_128_CBC:case t.ALGORITHM.AES_128_CCM:case t.ALGORITHM.AES_128_GCM:case t.ALGORITHM.AES_128_OCB:return{algorithm:a,keyLength:128/8};case t.ALGORITHM.AES_192_CBC:case t.ALGORITHM.AES_192_CCM:case t.ALGORITHM.AES_192_GCM:case t.ALGORITHM.AES_192_OCB:return{algorithm:a,keyLength:192/8};case t.ALGORITHM.AES_256_CBC:case t.ALGORITHM.AES_256_CCM:case t.ALGORITHM.AES_256_GCM:case t.ALGORITHM.AES_256_OCB:default:return{algorithm:a,keyLength:256/8}}}static IsGCM(a){return a===t.ALGORITHM.AES_128_GCM||a===t.ALGORITHM.AES_192_GCM||a===t.ALGORITHM.AES_256_GCM}static IsCCM(a){return a===t.ALGORITHM.AES_128_CCM||a===t.ALGORITHM.AES_192_CCM||a===t.ALGORITHM.AES_256_CCM}static IsChacha20Poly(a){return a===t.ALGORITHM.CHACHA_20_POLY}static IsOCB(a){return a===t.ALGORITHM.AES_128_OCB||a===t.ALGORITHM.AES_192_OCB||a===t.ALGORITHM.AES_256_OCB}static IsCBC(a){return a===t.ALGORITHM.AES_128_CBC||a===t.ALGORITHM.AES_192_CBC||a===t.ALGORITHM.AES_256_CBC}};t.SALT_LENGTH={min:16,max:64,default:32},t.IV_LENGTH={min:8,max:32,default:16},t.AUTH_TAG_LENGTH={min:4,max:16,default:16},t.AAD_LENGTH={min:16,max:128,default:32},t.ALGORITHM={AES_128_CBC:"aes-128-cbc",AES_192_CBC:"aes-192-cbc",AES_256_CBC:"aes-256-cbc",AES_128_CCM:"aes-128-ccm",AES_192_CCM:"aes-192-ccm",AES_256_CCM:"aes-256-ccm",AES_128_GCM:"aes-128-gcm",AES_192_GCM:"aes-192-gcm",AES_256_GCM:"aes-256-gcm",AES_128_OCB:"aes-128-ocb",AES_192_OCB:"aes-192-ocb",AES_256_OCB:"aes-256-ocb",CHACHA_20_POLY:"chacha20-poly1305"},t.DEFAULT_ALGORITHM={buffer:t.ALGORITHM.AES_256_GCM,stream:t.ALGORITHM.AES_256_CBC},t.ALGORITHMS=Object.values(t.ALGORITHM),t.stream={Encrypt(a,e){e.algorithm||(e.algorithm=t.DEFAULT_ALGORITHM.stream);let{Key:s,IV:r,salt:n,options:{input:o,output:c,algorithm:A}}=t.NewKeyIV({secret:a,...e}),p=i.createCipheriv(A,s,r);return c.write(Buffer.concat([n,r])),t.stream.Cipher({cipher:p,input:o,output:c})},async Decrypt(a,e){e.algorithm||(e.algorithm=t.DEFAULT_ALGORITHM.stream);let{input:s,output:r,algorithm:n,length:o,salt:c,iv:A}=t.ResolveOptions(e),[p,h]=await E(s,c+A),y=p.subarray(0,c),C=p.subarray(c),L=i.scryptSync(T(a),y,o),I=i.createDecipheriv(n,L,C);return t.stream.Decipher({decipher:I,input:h,output:r})},HybridEncrypt(a,e){e.algorithm||(e.algorithm=t.DEFAULT_ALGORITHM.stream);let{Key:s,IV:r,options:{algorithm:n,input:o,output:c}}=t.NewKeyIV(e),A=i.publicEncrypt({key:a,padding:i.constants.RSA_PKCS1_OAEP_PADDING,oaepHash:"sha256"},Buffer.concat([s,r])),p=i.createCipheriv(n,s,r);return t.stream.Cipher({cipher:p,encryptedKey:A,input:o,output:c})},HybridDecrypt(a,e){let{input:s,output:r}=e,{keyLength:n,algorithm:o}=t.GetKeyLength(e.algorithm||t.DEFAULT_ALGORITHM.stream);return new Promise((c,A)=>(s.on("error",A),r.on("error",A),t._stream.ExtractKeyLength(s).then(t._stream.ExtractKeyIV).then(([p,h])=>({...t.DecryptKeyIV({privateKey:a,EncryptedKeyIV:p,keyLength:n}),input:h})).then(async({Key:p,IV:h,input:y})=>{y.on("error",A);let C=i.createDecipheriv(o,p,h);await t.stream.Decipher({decipher:C,input:y,output:r}),c()}).catch(A)))},Cipher(a){let{cipher:e,encryptedKey:s,input:r,output:n}=a;return new Promise((o,c)=>{e.on("error",c),r.on("error",c),n.on("error",c),n.on("finish",o),s&&(n.write(m(s.length)),n.write(s)),r.pipe(e).pipe(n)})},Decipher(a){let{decipher:e,input:s,output:r}=a;return new Promise((n,o)=>{e.on("error",o),s.on("error",o),r.on("error",o),r.on("finish",n),s.pipe(e).pipe(r)})}},t._stream={ExtractKeyLength(a){return E(a,4).then(([e,s])=>[l(e),s])},ExtractKeyIV([a,e]){return E(e,a)}};var d=t;export{d as Cipher};