# README
Hyperledger Fabric chaincode kit (CCKit) - Envelope extension
The envelope extension allows to pass additional data with the request to check user signature and protect from replay attacks. The extension is implemented as cckit middleware.
Envelope structure
The envelope is a structure that consists of the following attributes:
- public_key - signer public key (bytes)
- signature - payload signature (bytes)
- nonce - number is given for replay protection (string)
- hash_to_sign - payload hash (bytes)
- hash_func - function used for hashing (string)
- deadline - signature is not valid after deadline, is not mandatory (timestamp)
- channel - chaincode channel
- chaincode - name of chaincode
- method - name of chaincode method
Channel + chaincode + method are used as domain separator to prevent replay attack from other domains (EIP-2612).
How the envelope works
Sign the message and send the envelope (usually on the frontend)
- Create the nonce
- Create the message to sign (include message payload and other attributes such as nonce, channel, chaincode, etc.)
- Hash the message (sha-256)
- Sign the hash (ed25519)
- Create the envelope
- Encode the envelope to base64
- Send the envelope in request header (X-Envelop) if the cckit gateway is used
Receive and transform the envelope (cckit gateway)
- Receive the envelope from request header
- Decode it from base64 and pack it as a third chaincode argument
Verify the signature (chaincode)
- Get the envelope as third argument
- Unmarshall the envelope
- Check envelope attributes (deadline, channel, chaincode, etc)
- Check the nonce
- Recreate the hash from the original message
- Verify the signature using pubkey from the envelope and the hash from the previous step
The sha-256 algorithm is used to hash the message.
The signature is generated using Ed25519.
How to use the envelope on chaincode
r := router.New(name).Use(envelope.Verify)
Create an envelope using js
const { sign } = require('tweetnacl');
const { createHash } = require('crypto');
const bs58 = require('bs58');
// CREATE ENVELOPE
function createEnvelope(
payload,
nonce,
channel,
chaincode,
method,
deadline,
keys
) {
const pk = bs58.encode(Buffer.from(keys.publicKey));
// make message to sign
const b1 = Buffer.from(JSON.stringify(payload));
const b2 = Buffer.from(nonce);
const b3 = Buffer.from(channel);
const b4 = Buffer.from(chaincode);
const b5 = Buffer.from(method);
const b6 = Buffer.from(deadline);
const b7 = Buffer.from(pk);
const arr = [b1, b2, b3, b4, b5, b6, b7];
const bb = Buffer.concat(arr);
// hash the message
const hashed = createHash('sha256').update(bb).digest();
// sign the hash
const signature = sign.detached(hashed, keys.secretKey);
// make the envelope
const envelope = {
hash_func: 'SHA256',
hash_to_sign: bs58.encode(hashed),
nonce: nonce,
channel: channel,
method: method,
chaincode: chaincode,
deadline: deadline,
public_key: pk,
signature: bs58.encode(Buffer.from(signature)),
};
console.log(JSON.stringify(envelope));
return JSON.stringify(envelope);
}
// MAIN
const payload = {
symbol: 'GLD',
decimals: '8',
name: 'Gold digital asset',
type: 'DM',
underlying_asset: 'gold',
issuer_id: 'GLDINC',
};
const chaincode = 'envelope-chaincode';
const channel = 'envelope-channel';
const method = 'invokeWithEnvelope';
const nonce = String(new Date().getTime());
const deadline = new Date(new Date().getTime() + 86400000).toISOString(); // if without deadline then use new Date(0).toISOString()
const keys = sign.keyPair();
const envelope = btoa(
createEnvelope(payload, nonce, channel, chaincode, method, deadline, keys)
);
# Packages
No description provided by the author
# Functions
No description provided by the author
decode base64 envelop.
handle custom header to pass envelope.
No description provided by the author
No description provided by the author
No description provided by the author
Verify is a middleware for checking signature in envelop.
input opt for gateway to handle envelope with signature.
# Constants
No description provided by the author
router context key.
No description provided by the author
# Variables
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
# Interfaces
No description provided by the author