| // 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 |
| } |