1'use strict'; 2 3const { 4 ObjectSetPrototypeOf, 5} = primordials; 6 7const { 8 ERR_CRYPTO_SIGN_KEY_REQUIRED, 9 ERR_INVALID_ARG_TYPE, 10 ERR_INVALID_OPT_VALUE 11} = require('internal/errors').codes; 12const { validateEncoding, validateString } = require('internal/validators'); 13const { 14 Sign: _Sign, 15 Verify: _Verify, 16 kSigEncDER, 17 kSigEncP1363, 18 signOneShot: _signOneShot, 19 verifyOneShot: _verifyOneShot 20} = internalBinding('crypto'); 21const { 22 getDefaultEncoding, 23 kHandle, 24 getArrayBufferView, 25} = require('internal/crypto/util'); 26const { 27 preparePrivateKey, 28 preparePublicOrPrivateKey 29} = require('internal/crypto/keys'); 30const { Writable } = require('stream'); 31const { isArrayBufferView } = require('internal/util/types'); 32 33function Sign(algorithm, options) { 34 if (!(this instanceof Sign)) 35 return new Sign(algorithm, options); 36 validateString(algorithm, 'algorithm'); 37 this[kHandle] = new _Sign(); 38 this[kHandle].init(algorithm); 39 40 Writable.call(this, options); 41} 42 43ObjectSetPrototypeOf(Sign.prototype, Writable.prototype); 44ObjectSetPrototypeOf(Sign, Writable); 45 46Sign.prototype._write = function _write(chunk, encoding, callback) { 47 this.update(chunk, encoding); 48 callback(); 49}; 50 51Sign.prototype.update = function update(data, encoding) { 52 encoding = encoding || getDefaultEncoding(); 53 54 if (typeof data === 'string') { 55 validateEncoding(data, encoding); 56 } else if (!isArrayBufferView(data)) { 57 throw new ERR_INVALID_ARG_TYPE( 58 'data', ['string', 'Buffer', 'TypedArray', 'DataView'], data); 59 } 60 61 this[kHandle].update(data, encoding); 62 return this; 63}; 64 65function getPadding(options) { 66 return getIntOption('padding', options); 67} 68 69function getSaltLength(options) { 70 return getIntOption('saltLength', options); 71} 72 73function getDSASignatureEncoding(options) { 74 if (typeof options === 'object') { 75 const { dsaEncoding = 'der' } = options; 76 if (dsaEncoding === 'der') 77 return kSigEncDER; 78 else if (dsaEncoding === 'ieee-p1363') 79 return kSigEncP1363; 80 throw new ERR_INVALID_OPT_VALUE('dsaEncoding', dsaEncoding); 81 } 82 83 return kSigEncDER; 84} 85 86function getIntOption(name, options) { 87 const value = options[name]; 88 if (value !== undefined) { 89 if (value === value >> 0) { 90 return value; 91 } 92 throw new ERR_INVALID_OPT_VALUE(name, value); 93 } 94 return undefined; 95} 96 97Sign.prototype.sign = function sign(options, encoding) { 98 if (!options) 99 throw new ERR_CRYPTO_SIGN_KEY_REQUIRED(); 100 101 const { data, format, type, passphrase } = preparePrivateKey(options, true); 102 103 // Options specific to RSA 104 const rsaPadding = getPadding(options); 105 const pssSaltLength = getSaltLength(options); 106 107 // Options specific to (EC)DSA 108 const dsaSigEnc = getDSASignatureEncoding(options); 109 110 const ret = this[kHandle].sign(data, format, type, passphrase, rsaPadding, 111 pssSaltLength, dsaSigEnc); 112 113 encoding = encoding || getDefaultEncoding(); 114 if (encoding && encoding !== 'buffer') 115 return ret.toString(encoding); 116 117 return ret; 118}; 119 120function signOneShot(algorithm, data, key) { 121 if (algorithm != null) 122 validateString(algorithm, 'algorithm'); 123 124 if (!isArrayBufferView(data)) { 125 throw new ERR_INVALID_ARG_TYPE( 126 'data', 127 ['Buffer', 'TypedArray', 'DataView'], 128 data 129 ); 130 } 131 132 if (!key) 133 throw new ERR_CRYPTO_SIGN_KEY_REQUIRED(); 134 135 const { 136 data: keyData, 137 format: keyFormat, 138 type: keyType, 139 passphrase: keyPassphrase 140 } = preparePrivateKey(key); 141 142 // Options specific to RSA 143 const rsaPadding = getPadding(key); 144 const pssSaltLength = getSaltLength(key); 145 146 // Options specific to (EC)DSA 147 const dsaSigEnc = getDSASignatureEncoding(key); 148 149 return _signOneShot(keyData, keyFormat, keyType, keyPassphrase, data, 150 algorithm, rsaPadding, pssSaltLength, dsaSigEnc); 151} 152 153function Verify(algorithm, options) { 154 if (!(this instanceof Verify)) 155 return new Verify(algorithm, options); 156 validateString(algorithm, 'algorithm'); 157 this[kHandle] = new _Verify(); 158 this[kHandle].init(algorithm); 159 160 Writable.call(this, options); 161} 162 163ObjectSetPrototypeOf(Verify.prototype, Writable.prototype); 164ObjectSetPrototypeOf(Verify, Writable); 165 166Verify.prototype._write = Sign.prototype._write; 167Verify.prototype.update = Sign.prototype.update; 168 169Verify.prototype.verify = function verify(options, signature, sigEncoding) { 170 const { 171 data, 172 format, 173 type, 174 passphrase 175 } = preparePublicOrPrivateKey(options, true); 176 177 sigEncoding = sigEncoding || getDefaultEncoding(); 178 179 // Options specific to RSA 180 const rsaPadding = getPadding(options); 181 const pssSaltLength = getSaltLength(options); 182 183 // Options specific to (EC)DSA 184 const dsaSigEnc = getDSASignatureEncoding(options); 185 186 signature = getArrayBufferView(signature, 'signature', sigEncoding); 187 188 return this[kHandle].verify(data, format, type, passphrase, signature, 189 rsaPadding, pssSaltLength, dsaSigEnc); 190}; 191 192function verifyOneShot(algorithm, data, key, signature) { 193 if (algorithm != null) 194 validateString(algorithm, 'algorithm'); 195 196 if (!isArrayBufferView(data)) { 197 throw new ERR_INVALID_ARG_TYPE( 198 'data', 199 ['Buffer', 'TypedArray', 'DataView'], 200 data 201 ); 202 } 203 204 const { 205 data: keyData, 206 format: keyFormat, 207 type: keyType, 208 passphrase: keyPassphrase 209 } = preparePublicOrPrivateKey(key); 210 211 // Options specific to RSA 212 const rsaPadding = getPadding(key); 213 const pssSaltLength = getSaltLength(key); 214 215 // Options specific to (EC)DSA 216 const dsaSigEnc = getDSASignatureEncoding(key); 217 218 if (!isArrayBufferView(signature)) { 219 throw new ERR_INVALID_ARG_TYPE( 220 'signature', 221 ['Buffer', 'TypedArray', 'DataView'], 222 signature 223 ); 224 } 225 226 return _verifyOneShot(keyData, keyFormat, keyType, keyPassphrase, signature, 227 data, algorithm, rsaPadding, pssSaltLength, dsaSigEnc); 228} 229 230module.exports = { 231 Sign, 232 signOneShot, 233 Verify, 234 verifyOneShot 235}; 236