-
Notifications
You must be signed in to change notification settings - Fork 26
Add concept of feed types for new signature / verification algorithms #61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
db4b6ed
5171233
79c0e98
a0ee48a
a3e1611
1534697
fb4be5c
2adcc13
da1aa08
b272b2b
37bcf09
4b89258
22a9efb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,7 @@ | ||
| 'use strict' | ||
| var sodium = require('chloride') | ||
|
|
||
| var pb = require('private-box') | ||
|
|
||
| var u = require('./util') | ||
|
|
||
| var isBuffer = Buffer.isBuffer | ||
|
|
||
| //UTILS | ||
|
|
@@ -22,57 +19,85 @@ var hmac = sodium.crypto_auth | |
|
|
||
| exports.hash = u.hash | ||
|
|
||
| exports.getTag = u.getTag | ||
| exports.getFeedType = u.getFeedType | ||
| exports.getTag = u.getFeedType // deprecated | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe add that annoying const warnings = [
'please no',
'naughty developer',
'I ask you to stop',
'I will stop working',
'I warn you'
]
var patience = warnings.length
exports.getTag = function () {
if (patience === 0) throw new Error('ssb-keys quits')
console.log(warnings[--patience])
return u.getFeedType()
} |
||
|
|
||
| function isObject (o) { | ||
| return 'object' === typeof o | ||
| } | ||
|
|
||
| function isFunction (f) { | ||
| return 'function' === typeof f | ||
| } | ||
|
|
||
| function isString(s) { | ||
| return 'string' === typeof s | ||
| } | ||
|
|
||
| var curves = {} | ||
| curves.ed25519 = require('./sodium') | ||
| const feedTypes = { | ||
| ed25519: require('./sodium'), | ||
| 'ed25519.test': require('./sodium') | ||
| } | ||
|
|
||
| exports.use = (name, object) => { | ||
| if (typeof name !== 'string' || name.length === 0) { | ||
| throw new Error(`Invalid name: "${name}", expected string with non-zero length`) | ||
| } | ||
|
|
||
| const requiredMethods = [ | ||
| 'generate', | ||
| 'sign', | ||
| 'verify' | ||
| ] | ||
|
|
||
| const isNotObject = typeof object !== 'object' | ||
| const isInvalidObject = isNotObject || requiredMethods.some(methodName => | ||
| typeof object[methodName] !== 'function' | ||
| ) | ||
|
|
||
| if (isInvalidObject) { | ||
| const expectedMethods = requiredMethods.join(', ') | ||
| console.log(object) | ||
| throw new Error(`Invalid object. Missing required methods, expected: ${expectedMethods}`) | ||
| } | ||
|
|
||
| if (feedTypes[name] != null) { | ||
| throw new Error(`Duplicate feed type: "${name}"`) | ||
| } | ||
|
|
||
| feedTypes[name] = object | ||
| } | ||
|
|
||
| function getCurve(keys) { | ||
| var curve = keys.curve | ||
| function getFeedType(keys) { | ||
| let { feedType } = keys | ||
| feedType = feedType || keys.curve | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
const {
feedType = keys.curve
} = keysactually this is a mess (it works well for destructuring multiple opts with defaults) const feedType = keys.feedType || keys.curve |
||
|
|
||
| if(!keys.curve && isString(keys.public)) | ||
| if(!feedType && isString(keys.public)) | ||
| keys = keys.public | ||
|
|
||
| if(!curve && isString(keys)) | ||
| curve = u.getTag(keys) | ||
| if(!feedType && isString(keys)) | ||
| feedType = u.getFeedType(keys) | ||
|
|
||
| if(!curves[curve]) { | ||
| throw new Error( | ||
| 'unkown curve:' + curve + | ||
| ' expected: '+Object.keys(curves) | ||
| ) | ||
| if(!feedTypes[feedType]) { | ||
| throw new Error(`unkown feed type: "${feedType}", expected: "${Object.keys(feedTypes)}"`) | ||
| } | ||
|
|
||
| return curve | ||
| return feedType | ||
| } | ||
|
|
||
| //this should return a key pair: | ||
| // {curve: curve, public: Buffer, private: Buffer} | ||
| // { feedType: string, curve: string, public: Buffer, private: Buffer} | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is a known requirement, then why don't you check this is what the |
||
| exports.generate = function (feedType, seed) { | ||
| feedType = feedType || 'ed25519' | ||
|
|
||
| exports.generate = function (curve, seed) { | ||
| curve = curve || 'ed25519' | ||
| if(feedTypes[feedType] == null) | ||
| throw new Error(`unknown feed type: "${feedType}"`) | ||
|
|
||
| if(!curves[curve]) | ||
| throw new Error('unknown curve:'+curve) | ||
|
|
||
| return u.keysToJSON(curves[curve].generate(seed), curve) | ||
| return u.keysToJSON(feedTypes[feedType].generate(seed), feedType) | ||
| } | ||
|
|
||
| //import functions for loading/saving keys from storage | ||
| var storage = require('./storage')(exports.generate) | ||
| for(var key in storage) exports[key] = storage[key] | ||
| exports.load = storage.load | ||
| exports.loadSync = storage.loadSync | ||
| exports.create = storage.create | ||
| exports.createSync = storage.createSync | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❤️ |
||
|
|
||
|
|
||
| exports.loadOrCreate = function (filename, cb) { | ||
|
|
@@ -96,14 +121,17 @@ exports.loadOrCreateSync = function (filename) { | |
|
|
||
| function sign (keys, msg) { | ||
| if(isString(msg)) | ||
| msg = new Buffer(msg) | ||
| msg = Buffer.from(msg) | ||
| if(!isBuffer(msg)) | ||
| throw new Error('msg should be buffer') | ||
| var curve = getCurve(keys) | ||
| var feedType = getFeedType(keys) | ||
|
|
||
| return curves[curve] | ||
| const prefix = feedTypes[feedType] | ||
| .sign(u.toBuffer(keys.private || keys), msg) | ||
| .toString('base64')+'.sig.'+curve | ||
| .toString('base64') | ||
| const suffix = `.sig.${feedType}` | ||
|
|
||
| return prefix + suffix | ||
|
|
||
| } | ||
|
|
||
|
|
@@ -112,10 +140,10 @@ function sign (keys, msg) { | |
| function verify (keys, sig, msg) { | ||
| if(isObject(sig)) | ||
| throw new Error('signature should be base64 string, did you mean verifyObj(public, signed_obj)') | ||
| return curves[getCurve(keys)].verify( | ||
| return feedTypes[getFeedType(keys)].verify( | ||
| u.toBuffer(keys.public || keys), | ||
| u.toBuffer(sig), | ||
| isBuffer(msg) ? msg : new Buffer(msg) | ||
| isBuffer(msg) ? msg : Buffer.from(msg) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
i.e. Buffer.from(msg, 'base64')
Buffer.from(msg, 'utf8') // I think this is the default |
||
| ) | ||
| } | ||
|
|
||
|
|
@@ -124,7 +152,7 @@ function verify (keys, sig, msg) { | |
| exports.signObj = function (keys, hmac_key, obj) { | ||
| if(!obj) obj = hmac_key, hmac_key = null | ||
| var _obj = clone(obj) | ||
| var b = new Buffer(JSON.stringify(_obj, null, 2)) | ||
| var b = Buffer.from(JSON.stringify(_obj, null, 2)) | ||
| if(hmac_key) b = hmac(b, u.toBuffer(hmac_key)) | ||
| _obj.signature = sign(keys, b) | ||
| return _obj | ||
|
|
@@ -135,13 +163,13 @@ exports.verifyObj = function (keys, hmac_key, obj) { | |
| obj = clone(obj) | ||
| var sig = obj.signature | ||
| delete obj.signature | ||
| var b = new Buffer(JSON.stringify(obj, null, 2)) | ||
| var b = Buffer.from(JSON.stringify(obj, null, 2)) | ||
| if(hmac_key) b = hmac(b, u.toBuffer(hmac_key)) | ||
| return verify(keys, sig, b) | ||
| } | ||
|
|
||
| exports.box = function (msg, recipients) { | ||
| msg = new Buffer(JSON.stringify(msg)) | ||
| msg = Buffer.from(JSON.stringify(msg)) | ||
|
|
||
| recipients = recipients.map(function (keys) { | ||
| return sodium.crypto_sign_ed25519_pk_to_curve25519(u.toBuffer(keys.public || keys)) | ||
|
|
@@ -163,7 +191,9 @@ exports.unboxBody = function (boxed, key) { | |
| var msg = pb.multibox_open_body(boxed, key) | ||
| try { | ||
| return JSON.parse(''+msg) | ||
| } catch (_) { } | ||
| } catch (_) { | ||
| return undefined | ||
| } | ||
| } | ||
|
|
||
| exports.unbox = function (boxed, keys) { | ||
|
|
@@ -174,8 +204,9 @@ exports.unbox = function (boxed, keys) { | |
| try { | ||
| var msg = pb.multibox_open(boxed, sk) | ||
| return JSON.parse(''+msg) | ||
| } catch (_) { } | ||
| return | ||
| } catch (_) { | ||
| return undefined | ||
| } | ||
| } | ||
|
|
||
| exports.secretBox = function secretBox (data, key) { | ||
|
|
@@ -188,4 +219,4 @@ exports.secretUnbox = function secretUnbox (ctxt, key) { | |
| var ptxt = sodium.crypto_secretbox_open_easy(ctxt, key.slice(0, 24), key) | ||
| if(!ptxt) return | ||
| return JSON.parse(ptxt.toString()) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been thinking about this recently with binary encoding of ids.
What I don't like about this is that
ed25519is a cryptographic curve thing... but that doesn't tell us anything about the feed type... like are the messages in this feed encoded as JSON, or are they some binary format? what's the spec for verifying thisfeedType?I calling this
feedType"classic", which happens to be ed25519 curve connection + signing, sha256 hashing, JSON encoding. "gabby" is anotherfeedTypewhich uses ed25519 but has some other stuff going on I gatherThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup, exactly. Same is true for the hash function.
In the protocol meetup last may we therefore renamed the SHA to „scuttlebutt happend anyway“.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was also going to comment about the
feedTypeand I might be a little late, but I think this is specifically referring to the type of encryption used in the message.So, isn't something like
encryptiona possible better name for this property?