New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@buckless/signed-data

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@buckless/signed-data - npm Package Compare versions

Comparing version 2.0.0 to 2.1.1

src/signedData.js

6

package.json
{
"name": "@buckless/signed-data",
"version": "2.0.0",
"description": "Sign data using HMAC-SHA1",
"version": "2.1.1",
"description": "Sign unsigned numbers using HMAC-SHA1",
"main": "src/index.js",
"repository": "https://github.com/buckless/signed-data.git",
"repository": "https://github.com/buckless/signed-number.git",
"author": "Gabriel Juchault <gabriel.juchault@gmail.com>",

@@ -8,0 +8,0 @@ "license": "MIT",

@@ -26,3 +26,3 @@ # signed-data

const inst = new SignedData({
const inst = new SignedData(
'secret', // signature key

@@ -41,3 +41,3 @@ null, // max bytes (defaults to: auto)

]
})
)

@@ -55,3 +55,3 @@ const cipher = inst.encode(value)

const inst = new SignedData({
const inst = new SignedData(
'secret', // signature key

@@ -70,3 +70,3 @@ null, // max bytes (defaults to: auto)

]
})
)

@@ -84,3 +84,3 @@ const cipher = inst.encode(value).toString('hex')

const inst = new SignedData({
const inst = new SignedData(
'secret', // signature key

@@ -99,3 +99,3 @@ 23, // (3 bytes of data + 20 bytes of signature)

]
})
)

@@ -115,3 +115,3 @@ const cipher = inst.encode(value)

const inst = new SignedData({
const inst = new SignedData(
'secret', // signature key

@@ -130,3 +130,3 @@ null, // max bytes (defaults to: auto)

]
})
)

@@ -146,2 +146,7 @@ const cipher = inst.encode(value)

```
# Override secret from constructor
key(secret: String)
```
```
encode(data: Object)

@@ -148,0 +153,0 @@ ```

@@ -1,106 +0,5 @@

const nativeSha1 = require('./nativeSha1')
const timingSafeEqual = require('./timingSafeEqual')
const MIN_HASH_BYTES = 4
const MAX_HASH_BYTES = 20
const SignedData = require('./signedData')
class SignedData {
constructor(secret, maxBytes, hashAlgorithm, scheme = []) {
if (typeof hashAlgorithm !== 'function') {
hashAlgorithm = nativeSha1
}
if (typeof secret !== 'string' || secret.length === 0) {
throw new Error('[signed-data] missing secret')
}
this.scheme = scheme
this.secret = secret
this.hashAlgorithm = hashAlgorithm
this.dataSize = this.scheme.map(p => p.size).reduce((a, b) => a + b, 0)
this.createHmac = require('hmac').bind(null, hashAlgorithm, 64)
this.maxBytes = maxBytes
? Math.min(this.dataSize + MAX_HASH_BYTES, Math.max(maxBytes, this.dataSize + MIN_HASH_BYTES))
: this.dataSize + MIN_HASH_BYTES
}
hmac() {
return this.createHmac(this.secret)
}
encode(data) {
let value = ''
for (let i = 0; i < this.scheme.length; i++) {
const part = this.scheme[i]
let result = data.hasOwnProperty(part.name)
? part.encode(data[part.name])
: part.default
if (result.length > part.size * 2) {
throw new Error(`[signed-data] encoder ${part.name} output a too large result`)
} else {
// left-pad
result = ('0'.repeat(part.size * 2) + result).slice(-1 * part.size * 2)
}
value += result
}
return this.sign(value)
}
sign(result) {
const hash = this.hmac().update(result, 'utf8').digest('hex')
return Buffer.from(`${result}${hash}`.slice(0, this.maxBytes * 2), 'hex')
}
decode(raw) {
let value = {}
let startIndex = 0
if (Buffer.isBuffer(raw)) {
raw = raw.toString('hex')
}
if (raw.length < this.dataSize * 2) {
throw new Error('[signed-data] data not found')
}
if (raw.length < this.maxBytes * 2) {
throw new Error('[signed-data] signature not found')
}
raw = raw.slice(0, this.maxBytes * 2)
if (!this.checkSignature(Buffer.from(raw, 'hex'))) {
throw new Error('[signed-data] signature does not match')
}
for (let i = 0; i < this.scheme.length; i++) {
const part = this.scheme[i]
let result = null
const data = part.decode(raw.slice(startIndex, startIndex + part.size * 2))
value[part.name] = data
startIndex += part.size * 2
}
return value
}
checkSignature(raw) {
const data = raw.slice(0, this.dataSize).toString('hex')
const signed = this.sign(data)
return timingSafeEqual(signed, raw)
}
module.exports = {
SignedData
}
module.exports = SignedData

@@ -6,11 +6,11 @@ // timingSafeEqual

if (!Buffer.isBuffer(a)) {
throw new Error('[signed-data] first argument must be a buffer')
throw new TypeError('[signed-data] first argument must be a buffer')
}
if (!Buffer.isBuffer(b)) {
throw new Error('[signed-data] second argument must be a buffer')
throw new TypeError('[signed-data] second argument must be a buffer')
}
if (a.length !== b.length) {
throw new Error('[signed-data] input buffers must have the same length')
throw new TypeError('[signed-data] input buffers must have the same length')
}

@@ -17,0 +17,0 @@

const test = require('tape')
const Rusha = require('rusha')
const mock = require('./mock')
const mockData = require('./mock.data')

@@ -10,10 +10,11 @@ test('Custom hash method using rusha', (t) => {

credit: 1500,
bools: { food: false, drink1: true, drink2: false }
catering: { food: false, drink1: true, drink2: false }
}
const inst = mock('secret', 12, Rusha.createHash)
const inst = mockData('mysecret', 12, Rusha.createHash)
const cipher = inst.encode(value)
const decipher = inst.decode(cipher)
t.deepEqual(decipher, value, 'decipher = value')
t.deepEqual(decipher, value, 'value = decipher')
})
const test = require('tape')
const mock = require('./mock')
const mockData = require('./mock.data')

@@ -7,68 +7,29 @@ test('Failing key', (t) => {

const value = {
const inst = mockData('mysecret')
const otherInst = mockData('othersecret')
const cipher = inst.encode({
credit: 1500,
bools: { food: false, drink1: true, drink2: false }
}
catering: { food: false, drink1: false, drink2: false }
})
const inst = mock('secret')
const otherInst = mock('othersecret')
const cipher = inst.encode(value)
try {
otherInst.decode(cipher)
} catch (e) {
t.equal(e.message, '[signed-data] signature does not match', 'error')
t.equal(e.message, '[signed-data] signature does not match')
}
})
test('No Data', (t) => {
test('Failing signature', (t) => {
t.plan(1)
const value = {
credit: 1500,
bools: { food: false, drink1: true, drink2: false }
}
const inst = mock('secret')
const cipher = inst.encode(value).slice(0, 2)
try {
inst.decode(cipher)
} catch (e) {
t.equal(e.message, '[signed-data] data not found', 'error')
}
})
test('No signature', (t) => {
t.plan(1)
const value = {
credit: 1500,
bools: { food: false, drink1: true, drink2: false }
}
const inst = mock('secret')
const cipher = inst.encode(value).slice(0, inst.dataSize)
try {
inst.decode(cipher)
} catch (e) {
t.equal(e.message, '[signed-data] signature not found', 'error')
}
})
test('Modified signature', (t) => {
t.plan(1)
const value = {
credit: 1500,
bools: { food: false, drink1: true, drink2: false }
}
const inst = mock('secret')
const cipher = inst
.encode(value)
const inst = mockData('mysecret')
let cipher = inst
.encode({
credit: 1500,
catering: { food: false, drink1: false, drink2: false }
})
.toString('hex')
.replace(/.$/, 'f') // 0005dc024be23567 -> 0005dc024be2356f
// replace last char (n) with (n + 1) to ensure the signature fails
cipher = cipher.replace(/.$/, ((parseInt(cipher[cipher.length - 1], 16) + 1) % 16).toString(16))

@@ -78,4 +39,4 @@ try {

} catch (e) {
t.equal(e.message, '[signed-data] signature does not match', 'error')
t.equal(e.message, '[signed-data] signature does not match')
}
})
const test = require('tape')
const mock = require('./mock')
const mockData = require('./mock.data')
test('Missing secret (empty string)', (t) => {
t.plan(1)
test('Missing or invalid secret', (t) => {
t.plan(4)
const value = {
credit: 123131313123,
bools: { food: false, drink1: false, drink2: false }
try {
const inst = mockData()
inst.encode(1500)
} catch (e) {
t.equal(e.message, '[signed-data] Missing argument secret, or secret is not a string', 'throw error for a missing key')
}
try {
mock('')
const inst = mockData(null)
inst.encode(1500)
} catch (e) {
t.equal(e.message, '[signed-data] missing secret', 'error')
t.equal(e.message, '[signed-data] Missing argument secret, or secret is not a string', 'throw error for a missing key')
}
})
test('Missing secret (non-string)', (t) => {
t.plan(1)
const value = {
credit: 123131313123,
bools: { food: false, drink1: false, drink2: false }
}
try {
mock(0)
const inst = mockData(123)
inst.encode(1500)
} catch (e) {
t.equal(e.message, '[signed-data] missing secret', 'error')
t.equal(e.message, '[signed-data] Missing argument secret, or secret is not a string', 'throw error for a missing key')
}
})
test('Missing secret (undefined)', (t) => {
t.plan(1)
const value = {
credit: 123131313123,
bools: { food: false, drink1: false, drink2: false }
}
try {
mock()
const inst = mockData('')
inst.encode(1500)
} catch (e) {
t.equal(e.message, '[signed-data] missing secret', 'error')
t.equal(e.message, '[signed-data] Missing argument secret, or secret is not a string', 'throw error for a missing key')
}
})
const test = require('tape')
const mock = require('./mock')
const mockData = require('./mock.data')

@@ -8,12 +8,13 @@ test('Usage', (t) => {

const value = {
credit: 1500,
bools: { food: false, drink1: true, drink2: false }
credit: 0,
catering: { food: false, drink1: true, drink2: true }
}
const inst = mock('secret')
const inst = mockData('mysecret')
const cipher = inst.encode(value)
const decipher = inst.decode(cipher)
t.equal(8, cipher.length, 'length = 8')
t.deepEqual(decipher, value, 'decipher = value')
t.equal(8, cipher.length, 'cipher length === 8')
t.deepEqual(decipher, value, 'decipher === value')
})

@@ -25,12 +26,13 @@

const value = {
credit: 1500,
bools: { food: false, drink1: true, drink2: false }
credit: 0,
catering: { food: false, drink1: true, drink2: true }
}
const inst = mock('secret')
const inst = mockData('mysecret')
const cipher = inst.encode(value).toString('hex')
const decipher = inst.decode(cipher)
t.equal(8, cipher.length / 2, 'length = 8')
t.deepEqual(decipher, value, 'decipher = value')
t.equal(8, cipher.length / 2, 'cipher length === 8')
t.deepEqual(decipher, value, 'decipher === value')
})

@@ -42,27 +44,29 @@

const value = {
credit: 1500,
bools: { food: false, drink1: true, drink2: false }
credit: 0,
catering: { food: false, drink1: true, drink2: true }
}
const inst = mock('secret', 20)
const inst = mockData('mysecret', 20)
const cipher = inst.encode(value)
const decipher = inst.decode(cipher)
t.equal(20, cipher.length, 'length = 20')
t.deepEqual(decipher, value, 'decipher = value')
t.equal(20, cipher.length, 'cipher length === 20')
t.deepEqual(decipher, value, 'decipher === value')
})
test('Usage — With random data at the end', (t) => {
test('Usage — More signature', (t) => {
t.plan(1)
const value = {
credit: 1500,
bools: { food: false, drink1: true, drink2: false }
credit: 0,
catering: { food: false, drink1: true, drink2: true }
}
const inst = mock('secret', 20)
const inst = mockData('mysecret', 14)
const cipher = inst.encode(value).toString('hex') + Math.ceil(Math.random() * 1000000)
const decipher = inst.decode(cipher)
t.deepEqual(decipher, value, 'decipher = value')
t.deepEqual(decipher, value, 'decipher === value')
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc