envelope

package
v1.0.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 25, 2024 License: Apache-2.0 Imports: 25 Imported by: 0

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)
  1. Create the nonce
  2. Create the message to sign (include message payload and other attributes such as nonce, channel, chaincode, etc.)
  3. Hash the message (sha-256)
  4. Sign the hash (ed25519)
  5. Create the envelope
  6. Encode the envelope to base64
  7. Send the envelope in request header (X-Envelop) if the cckit gateway is used
Receive and transform the envelope (cckit gateway)
  1. Receive the envelope from request header
  2. Decode it from base64 and pack it as a third chaincode argument
Verify the signature (chaincode)
  1. Get the envelope as third argument
  2. Unmarshall the envelope
  3. Check envelope attributes (deadline, channel, chaincode, etc)
  4. Check the nonce
  5. Recreate the hash from the original message
  6. 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)
);

Documentation

Index

Constants

View Source
const (
	TimeLayout = "2006-01-02T15:04:05.000Z"

	PubKey string = "envelopePubkey" // router context key
)
View Source
const HeaderKey = "X-Envelope"

Variables

View Source
var (
	ErrSignatureNotFound = errors.New(`signature not found`)

	ErrSignatureCheckFailed = errors.New(`check signature failed`)

	ErrDeadlineExpired = errors.New(`deadline expired`)

	ErrCheckSignatureFailed = errors.New(`check signature failed`)

	ErrTxAlreadyExecuted = errors.New(`tx already executed`)

	ErrInvalidMethod = errors.New(`invalid method in envelope`)

	ErrInvalidChannel = errors.New(`invalid channel in envelope`)
)
View Source
var File_envelope_envelope_proto protoreflect.FileDescriptor

Functions

func CreateNonce

func CreateNonce() string

func DecodeEnvelope

func DecodeEnvelope(encEnvelope []byte) ([]byte, error)

decode base64 envelop

func EnvelopeMatcher

func EnvelopeMatcher(key string) (string, bool)

handle custom header to pass envelope

func PrepareToHash added in v1.0.5

func PrepareToHash(payload []byte, nonce, channel, chaincode, method, deadline string, pubkey []byte) []byte

func Sign added in v1.0.5

func Sign(crypto crypto.Crypto, payload []byte, nonce, channel, chaincode, method, deadline string, privateKey []byte) ([]byte, error)

func Verify

func Verify(verifier Verifier) router.MiddlewareFunc

Verify is a middleware for checking signature in envelop

func WithEnvelope

func WithEnvelope() gateway.Opt

input opt for gateway to handle envelope with signature

Types

type DefaultVerifier added in v1.0.5

type DefaultVerifier struct {
	// contains filtered or unexported fields
}

func NewVerifier added in v1.0.5

func NewVerifier(verifier crypto.Verifier) *DefaultVerifier

func (*DefaultVerifier) Verify added in v1.0.5

func (s *DefaultVerifier) Verify(payload []byte, nonce, channel, chaincode, method, deadline string, pubKey []byte, sig []byte) error

type Envelope

type Envelope struct {
	PublicKey  string                 `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`      // signer public key in base58
	Signature  string                 `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`                       // payload signature in base58
	Nonce      string                 `protobuf:"bytes,3,opt,name=nonce,proto3" json:"nonce,omitempty"`                               // number is given for replay protection
	HashToSign string                 `protobuf:"bytes,4,opt,name=hash_to_sign,json=hashToSign,proto3" json:"hash_to_sign,omitempty"` // payload hash in base58
	HashFunc   string                 `protobuf:"bytes,5,opt,name=hash_func,json=hashFunc,proto3" json:"hash_func,omitempty"`         // function used for hashing
	Deadline   *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=deadline,proto3" json:"deadline,omitempty"`                         // signature is not valid after deadline (EIP-2612)
	// channel + chaincode + method are used as domain separator to prevent replay attack from other domains (EIP-2612)
	Channel      string `protobuf:"bytes,7,opt,name=channel,proto3" json:"channel,omitempty"`
	Chaincode    string `protobuf:"bytes,8,opt,name=chaincode,proto3" json:"chaincode,omitempty"`
	Method       string `protobuf:"bytes,9,opt,name=method,proto3" json:"method,omitempty"`
	SignatureAlg string `protobuf:"bytes,10,opt,name=signature_alg,json=signatureAlg,proto3" json:"signature_alg,omitempty"`
	// contains filtered or unexported fields
}

func (*Envelope) Descriptor deprecated

func (*Envelope) Descriptor() ([]byte, []int)

Deprecated: Use Envelope.ProtoReflect.Descriptor instead.

func (*Envelope) GetChaincode

func (x *Envelope) GetChaincode() string

func (*Envelope) GetChannel

func (x *Envelope) GetChannel() string

func (*Envelope) GetDeadline

func (x *Envelope) GetDeadline() *timestamppb.Timestamp

func (*Envelope) GetHashFunc

func (x *Envelope) GetHashFunc() string

func (*Envelope) GetHashToSign

func (x *Envelope) GetHashToSign() string

func (*Envelope) GetMethod

func (x *Envelope) GetMethod() string

func (*Envelope) GetNonce

func (x *Envelope) GetNonce() string

func (*Envelope) GetPublicKey

func (x *Envelope) GetPublicKey() string

func (*Envelope) GetSignature

func (x *Envelope) GetSignature() string

func (*Envelope) GetSignatureAlg added in v1.0.5

func (x *Envelope) GetSignatureAlg() string

func (*Envelope) ProtoMessage

func (*Envelope) ProtoMessage()

func (*Envelope) ProtoReflect

func (x *Envelope) ProtoReflect() protoreflect.Message

func (*Envelope) Reset

func (x *Envelope) Reset()

func (*Envelope) String

func (x *Envelope) String() string

func (*Envelope) Validate added in v1.0.2

func (this *Envelope) Validate() error

type Verifier added in v1.0.5

type Verifier interface {
	Verify(payload []byte, nonce, channel, chaincode, method, deadline string, publicKey []byte, sig []byte) error
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL