blob: cfb7b05ebd06b79110e9fdbda4b2862c8830c890 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package documents
import (
"bytes"
"fmt"
"github.com/apache/incubator-milagro-dta/libs/crypto"
"github.com/apache/incubator-milagro-dta/libs/cryptowallet"
proto "github.com/golang/protobuf/proto"
"github.com/pkg/errors"
)
var (
errRecipientNotFound = errors.New("Recipient not found")
errFailedDecapsulation = errors.New("Failed to decapsulate AES key")
errFailedToGenerateAESKey = errors.New("Failed to generate Random aesKey")
)
//decapsulate - decapsulate the aes for Recipient ID in the list
func decapsulate(recipientCID string, recipients []*Recipient, sikeSK []byte) ([]byte, error) {
for _, recipient := range recipients {
if recipient.CID == recipientCID {
return decapsulateWithRecipient(*recipient, sikeSK)
}
}
return nil, errRecipientNotFound
}
func decapsulateWithRecipient(recipient Recipient, sikeSK []byte) ([]byte, error) {
cipherText := recipient.CipherText
encapsulatedKey := recipient.EncapsulatedKey
encapIV := recipient.IV
rc, recreatedAesKey := crypto.DecapsulateDecrypt(cipherText, encapIV, sikeSK, encapsulatedKey)
if rc != 0 {
return nil, errFailedDecapsulation
}
return recreatedAesKey, nil
}
func encapsulateKeyForRecipient(recipientsIDDocs map[string]*IDDoc, secret []byte) (recipientList []*Recipient, err error) {
for id, idDocument := range recipientsIDDocs {
r := &Recipient{}
iv, err := cryptowallet.RandomBytes(16)
if err != nil {
return nil, errFailedToGenerateAESKey
}
r.CID = id
r.IV = iv
sikePK := idDocument.SikePublicKey
rc, cipherText, encapsulatedKey := crypto.EncapsulateEncrypt(secret, iv, sikePK)
if rc != 0 {
return nil, errFailedToGenerateAESKey
}
r.EncapsulatedKey = encapsulatedKey
r.CipherText = cipherText
recipientList = append(recipientList, r)
}
return recipientList, nil
}
func aesEncrypt(plainText []byte) (cipherText []byte, aesKey []byte, iv []byte, err error) {
aesKey, err = cryptowallet.RandomBytes(32)
if err != nil {
return nil, nil, nil, errFailedToGenerateAESKey
}
iv, err = cryptowallet.RandomBytes(16)
if err != nil {
return nil, nil, nil, errFailedToGenerateAESKey
}
paddedText, err := pkcs7Pad(plainText, 32)
if err != nil {
return nil, nil, nil, errors.Wrap(err, "Failed to pad Document secret")
}
cipherText = crypto.AESCBCEncrypt(aesKey, iv, paddedText)
return cipherText, aesKey, iv, nil
}
func aesDecrypt(cipherText []byte, iv []byte, aesKey []byte) (plainText []byte, err error) {
pt := crypto.AESCBCDecrypt(aesKey, iv, cipherText)
plainText, err = pkcs7Unpad(pt, 32)
if err != nil {
return nil, err
}
return plainText, nil
}
//Sign - generate a Signed envelope from the envelope
func sign(envelope Envelope, blsSK []byte, signerNodeID string) (SignedEnvelope, error) {
envelopeBytes, err := proto.Marshal(&envelope)
if err != nil {
return SignedEnvelope{}, errors.Wrap(err, "Failed to serialize envelope in SignBLS")
}
rc, signature := crypto.BLSSign(envelopeBytes, blsSK)
if rc != 0 {
return SignedEnvelope{}, errors.Wrap(err, "Failed to sign envelope in in SignBLS")
}
signedEnvelope := SignedEnvelope{}
signedEnvelope.SignerCID = signerNodeID
signedEnvelope.Message = envelopeBytes
signedEnvelope.Signature = signature
return signedEnvelope, nil
}
//Verify verify the envelopes BLS signature
func Verify(signedEnvelope SignedEnvelope, blsPK []byte) error {
message := signedEnvelope.Message
signature := signedEnvelope.Signature
rc := crypto.BLSVerify(message, blsPK, signature)
if rc == 0 {
return nil
}
return errors.New("invalid signature")
}
// Appends padding.
func pkcs7Pad(data []byte, blocklen int) ([]byte, error) {
if blocklen <= 0 {
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
}
padlen := 1
for ((len(data) + padlen) % blocklen) != 0 {
padlen = padlen + 1
}
pad := bytes.Repeat([]byte{byte(padlen)}, padlen)
return append(data, pad...), nil
}
// Returns slice of the original data without padding.
func pkcs7Unpad(data []byte, blocklen int) ([]byte, error) {
if blocklen <= 0 {
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
}
if len(data)%blocklen != 0 || len(data) == 0 {
return nil, fmt.Errorf("invalid data len %d", len(data))
}
padlen := int(data[len(data)-1])
if padlen > blocklen || padlen == 0 {
return nil, fmt.Errorf("invalid padding")
}
// check padding
pad := data[len(data)-padlen:]
for i := 0; i < padlen; i++ {
if pad[i] != byte(padlen) {
return nil, fmt.Errorf("invalid padding")
}
}
return data[:len(data)-padlen], nil
}