From e22fae05f7a101d1acaa71d36c3c2b4d9d0b4ffd Mon Sep 17 00:00:00 2001 From: Sudhi Herle Date: Mon, 23 Mar 2020 10:44:40 -0700 Subject: [PATCH] Better handling of sender verification * Sender identity is never shared in the encrypted payload * Sender signs the data-encryption key via Ed25519 if sender-auth is desired; else a "signature" of all zeroes is used. In either case, this signature is encrypted with the same data-encryption key. * cleaned up stale code and updated tests --- README.md | 50 +++---- crypt.go | 12 +- internal/pb/hdr.pb.go | 307 ++++++++--------------------------------- internal/pb/hdr.proto | 19 +-- internal/pb/wrap.go | 97 ------------- sign/encrypt.go | 310 +++++++++++++++++++++++++++--------------- sign/keys.go | 18 +-- sign/sign.go | 12 +- sign/sign_test.go | 18 +-- version | 2 +- 10 files changed, 324 insertions(+), 521 deletions(-) delete mode 100644 internal/pb/wrap.go diff --git a/README.md b/README.md index 12564dc..493bcd7 100644 --- a/README.md +++ b/README.md @@ -138,11 +138,7 @@ recipient can decrypt using their private key. ## Technical Details -### How is the private key protected? -The Ed25519 private key is encrypted in AES-GCM-256 mode using a key -derived from the user's pass-phrase. - -### How is the Encryption done? +### How is the file encryption done? The file encryption uses AES-GCM-256 in AEAD mode. The encryption uses a random 32-byte AES-256 key. This key is mixed in with the header checksum as a safeguard to protect the header against accidental or malicious corruption. @@ -152,13 +148,19 @@ its own nonce from a global salt. The nonce is calculated as a SHA256 hash of the salt, the chunk length and the block number. ### What is the public-key cryptography? -`sigtool` uses Curve25519 ECC to generate shared secrets between -pairs of sender & recipients. This pairwise shared secret is expanded -using HKDF to generate a key-encryption-key. The file-encryption key -is AEAD encrypted with this key-encryption-key. Thus, each recipient -has their own individual encrypted key blob. +`sigtool` uses ephemeral Curve25519 keys to generate shared secrets +between pairs of sender & one or more recipients. This pairwise shared +secret is used as a key-encryption-key (KEK) to encrypt the +data-encryption key in AEAD mode. Thus, each recipient has their own +individual encrypted key blob. -The Ed25519 keys generated by `sigtool` are transformed to their +If the sender authenticates the encryption by providing their secret +key, the data-encryption key is signed via Ed25519 and the signature +is encrypted (using the data-encryption key) and stored in the +header. If the sender opts to not authenticate, a "signature" of all +zeroes is encrypted instead. + +The Ed25519 keys generated by `sigtool` or OpenSSH are transformed to their corresponding Curve25519 points in order to generate the shared secret. This elliptic co-ordinate transform follows [FiloSottile's writeup][2]. @@ -180,18 +182,11 @@ described as a protobuf file (sign/hdr.proto): ```protobuf message header { - uint32 chunk_size = 1; - bytes salt = 2; - bytes pk = 3; // sender's ephemeral curve PK - sender sender_pk = 4; // sender's encrypted ed25519 PK - repeated wrapped_key keys = 5; - } - - /* - * Sender info is wrapped using the data encryption key - */ - message sender { - bytes pk = 1; + uint32 chunk_size = 1; + bytes salt = 2; + bytes pk = 3; // sender's ephemeral curve PK + bytes sender_sig = 4; // ed25519 signature of the key + repeated wrapped_key keys = 5; } /* @@ -199,7 +194,7 @@ described as a protobuf file (sign/hdr.proto): * key. WrappedKey describes such a wrapped key. */ message wrapped_key { - bytes key = 2; + bytes d_key = 1; } ``` @@ -220,6 +215,11 @@ computed. The chunk data and AEAD tag are treated as an atomic unit for AEAD decryption. +### How is the private key protected? +The Ed25519 private key is encrypted in AES-GCM-256 mode using a key +derived from the user's pass-phrase. + + ## Understanding the Code The core logic is in `src/sign`: it is a library that exposes all the functionality: key generation, key parsing, signing, encryption, decryption @@ -230,7 +230,7 @@ etc. * `src/keys.go` contains key generation, serialization, de-serialization * `src/ssh.go` contains code to parse SSH Ed25519 key files * `src/stream.go` contains code that provides an `io.Reader` and `io.WriteCloser` interface - for encryption and decryption. + for encryption and decryption. The generated keys and signatures are proper YAML files and human readable. diff --git a/crypt.go b/crypt.go index d1e59e4..795dea8 100644 --- a/crypt.go +++ b/crypt.go @@ -43,7 +43,7 @@ func encrypt(args []string) { fs.StringVarP(&keyfile, "sign", "s", "", "Sign using private key `S`") fs.BoolVarP(&nopw, "no-password", "", false, "Don't ask for passphrase to decrypt the private key") fs.StringVarP(&envpw, "env-password", "", "", "Use passphrase from environment variable `E`") - fs.SizeVarP(&blksize, "block-size", "B", 128 * 1024, "Use `S` as the encryption block size") + fs.SizeVarP(&blksize, "block-size", "B", 128*1024, "Use `S` as the encryption block size") err := fs.Parse(args) if err != nil { @@ -264,7 +264,7 @@ func decrypt(args []string) { infd = inf } } - + if test { outfd = &nullWriter{} } else if len(outfile) > 0 && outfile != "-" { @@ -298,6 +298,14 @@ func decrypt(args []string) { die("%s", err) } + if pk == nil && d.AuthenticatedSender() { + var fn string = infile + if len(fn) == 0 || fn == "-" { + fn = "" + } + warn("%s: Missing sender Public Key; can't authenticate sender ..", fn) + } + err = d.Decrypt(outfd) if err != nil { die("%s", err) diff --git a/internal/pb/hdr.pb.go b/internal/pb/hdr.pb.go index a4817d4..66e6432 100644 --- a/internal/pb/hdr.pb.go +++ b/internal/pb/hdr.pb.go @@ -10,7 +10,6 @@ It has these top-level messages: Header - Sender WrappedKey */ package pb @@ -43,11 +42,11 @@ const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package // decoded version of this information. It is encoded in // protobuf format before writing to disk. type Header struct { - ChunkSize uint32 `protobuf:"varint,1,opt,name=chunk_size,json=chunkSize,proto3" json:"chunk_size,omitempty"` - Salt []byte `protobuf:"bytes,2,opt,name=salt,proto3" json:"salt,omitempty"` - Pk []byte `protobuf:"bytes,3,opt,name=pk,proto3" json:"pk,omitempty"` - SenderPk *Sender `protobuf:"bytes,4,opt,name=sender_pk,json=senderPk" json:"sender_pk,omitempty"` - Keys []*WrappedKey `protobuf:"bytes,5,rep,name=keys" json:"keys,omitempty"` + ChunkSize uint32 `protobuf:"varint,1,opt,name=chunk_size,json=chunkSize,proto3" json:"chunk_size,omitempty"` + Salt []byte `protobuf:"bytes,2,opt,name=salt,proto3" json:"salt,omitempty"` + Pk []byte `protobuf:"bytes,3,opt,name=pk,proto3" json:"pk,omitempty"` + SenderSign []byte `protobuf:"bytes,4,opt,name=sender_sign,json=senderSign,proto3" json:"sender_sign,omitempty"` + Keys []*WrappedKey `protobuf:"bytes,5,rep,name=keys" json:"keys,omitempty"` } func (m *Header) Reset() { *m = Header{} } @@ -75,9 +74,9 @@ func (m *Header) GetPk() []byte { return nil } -func (m *Header) GetSenderPk() *Sender { +func (m *Header) GetSenderSign() []byte { if m != nil { - return m.SenderPk + return m.SenderSign } return nil } @@ -89,44 +88,26 @@ func (m *Header) GetKeys() []*WrappedKey { return nil } -// -// Sender info is wrapped using the data encryption key -type Sender struct { - Pk []byte `protobuf:"bytes,1,opt,name=pk,proto3" json:"pk,omitempty"` -} - -func (m *Sender) Reset() { *m = Sender{} } -func (*Sender) ProtoMessage() {} -func (*Sender) Descriptor() ([]byte, []int) { return fileDescriptorHdr, []int{1} } - -func (m *Sender) GetPk() []byte { - if m != nil { - return m.Pk - } - return nil -} - // // A file encryption key is wrapped by a recipient specific public // key. WrappedKey describes such a wrapped key. type WrappedKey struct { - Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + DKey []byte `protobuf:"bytes,1,opt,name=d_key,json=dKey,proto3" json:"d_key,omitempty"` } func (m *WrappedKey) Reset() { *m = WrappedKey{} } func (*WrappedKey) ProtoMessage() {} -func (*WrappedKey) Descriptor() ([]byte, []int) { return fileDescriptorHdr, []int{2} } +func (*WrappedKey) Descriptor() ([]byte, []int) { return fileDescriptorHdr, []int{1} } -func (m *WrappedKey) GetKey() []byte { +func (m *WrappedKey) GetDKey() []byte { if m != nil { - return m.Key + return m.DKey } return nil } func init() { proto.RegisterType((*Header)(nil), "pb.header") - proto.RegisterType((*Sender)(nil), "pb.sender") proto.RegisterType((*WrappedKey)(nil), "pb.wrapped_key") } func (this *Header) Equal(that interface{}) bool { @@ -163,7 +144,7 @@ func (this *Header) Equal(that interface{}) bool { if !bytes.Equal(this.Pk, that1.Pk) { return false } - if !this.SenderPk.Equal(that1.SenderPk) { + if !bytes.Equal(this.SenderSign, that1.SenderSign) { return false } if len(this.Keys) != len(that1.Keys) { @@ -176,36 +157,6 @@ func (this *Header) Equal(that interface{}) bool { } return true } -func (this *Sender) Equal(that interface{}) bool { - if that == nil { - if this == nil { - return true - } - return false - } - - that1, ok := that.(*Sender) - if !ok { - that2, ok := that.(Sender) - if ok { - that1 = &that2 - } else { - return false - } - } - if that1 == nil { - if this == nil { - return true - } - return false - } else if this == nil { - return false - } - if !bytes.Equal(this.Pk, that1.Pk) { - return false - } - return true -} func (this *WrappedKey) Equal(that interface{}) bool { if that == nil { if this == nil { @@ -231,7 +182,7 @@ func (this *WrappedKey) Equal(that interface{}) bool { } else if this == nil { return false } - if !bytes.Equal(this.Key, that1.Key) { + if !bytes.Equal(this.DKey, that1.DKey) { return false } return true @@ -245,32 +196,20 @@ func (this *Header) GoString() string { s = append(s, "ChunkSize: "+fmt.Sprintf("%#v", this.ChunkSize)+",\n") s = append(s, "Salt: "+fmt.Sprintf("%#v", this.Salt)+",\n") s = append(s, "Pk: "+fmt.Sprintf("%#v", this.Pk)+",\n") - if this.SenderPk != nil { - s = append(s, "SenderPk: "+fmt.Sprintf("%#v", this.SenderPk)+",\n") - } + s = append(s, "SenderSign: "+fmt.Sprintf("%#v", this.SenderSign)+",\n") if this.Keys != nil { s = append(s, "Keys: "+fmt.Sprintf("%#v", this.Keys)+",\n") } s = append(s, "}") return strings.Join(s, "") } -func (this *Sender) GoString() string { - if this == nil { - return "nil" - } - s := make([]string, 0, 5) - s = append(s, "&pb.Sender{") - s = append(s, "Pk: "+fmt.Sprintf("%#v", this.Pk)+",\n") - s = append(s, "}") - return strings.Join(s, "") -} func (this *WrappedKey) GoString() string { if this == nil { return "nil" } s := make([]string, 0, 5) s = append(s, "&pb.WrappedKey{") - s = append(s, "Key: "+fmt.Sprintf("%#v", this.Key)+",\n") + s = append(s, "DKey: "+fmt.Sprintf("%#v", this.DKey)+",\n") s = append(s, "}") return strings.Join(s, "") } @@ -314,15 +253,11 @@ func (m *Header) MarshalTo(dAtA []byte) (int, error) { i = encodeVarintHdr(dAtA, i, uint64(len(m.Pk))) i += copy(dAtA[i:], m.Pk) } - if m.SenderPk != nil { + if len(m.SenderSign) > 0 { dAtA[i] = 0x22 i++ - i = encodeVarintHdr(dAtA, i, uint64(m.SenderPk.Size())) - n1, err := m.SenderPk.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n1 + i = encodeVarintHdr(dAtA, i, uint64(len(m.SenderSign))) + i += copy(dAtA[i:], m.SenderSign) } if len(m.Keys) > 0 { for _, msg := range m.Keys { @@ -339,30 +274,6 @@ func (m *Header) MarshalTo(dAtA []byte) (int, error) { return i, nil } -func (m *Sender) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Sender) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if len(m.Pk) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintHdr(dAtA, i, uint64(len(m.Pk))) - i += copy(dAtA[i:], m.Pk) - } - return i, nil -} - func (m *WrappedKey) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -378,11 +289,11 @@ func (m *WrappedKey) MarshalTo(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.Key) > 0 { - dAtA[i] = 0x12 + if len(m.DKey) > 0 { + dAtA[i] = 0xa i++ - i = encodeVarintHdr(dAtA, i, uint64(len(m.Key))) - i += copy(dAtA[i:], m.Key) + i = encodeVarintHdr(dAtA, i, uint64(len(m.DKey))) + i += copy(dAtA[i:], m.DKey) } return i, nil } @@ -428,8 +339,8 @@ func (m *Header) Size() (n int) { if l > 0 { n += 1 + l + sovHdr(uint64(l)) } - if m.SenderPk != nil { - l = m.SenderPk.Size() + l = len(m.SenderSign) + if l > 0 { n += 1 + l + sovHdr(uint64(l)) } if len(m.Keys) > 0 { @@ -441,20 +352,10 @@ func (m *Header) Size() (n int) { return n } -func (m *Sender) Size() (n int) { - var l int - _ = l - l = len(m.Pk) - if l > 0 { - n += 1 + l + sovHdr(uint64(l)) - } - return n -} - func (m *WrappedKey) Size() (n int) { var l int _ = l - l = len(m.Key) + l = len(m.DKey) if l > 0 { n += 1 + l + sovHdr(uint64(l)) } @@ -482,28 +383,18 @@ func (this *Header) String() string { `ChunkSize:` + fmt.Sprintf("%v", this.ChunkSize) + `,`, `Salt:` + fmt.Sprintf("%v", this.Salt) + `,`, `Pk:` + fmt.Sprintf("%v", this.Pk) + `,`, - `SenderPk:` + strings.Replace(fmt.Sprintf("%v", this.SenderPk), "Sender", "Sender", 1) + `,`, + `SenderSign:` + fmt.Sprintf("%v", this.SenderSign) + `,`, `Keys:` + strings.Replace(fmt.Sprintf("%v", this.Keys), "WrappedKey", "WrappedKey", 1) + `,`, `}`, }, "") return s } -func (this *Sender) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&Sender{`, - `Pk:` + fmt.Sprintf("%v", this.Pk) + `,`, - `}`, - }, "") - return s -} func (this *WrappedKey) String() string { if this == nil { return "nil" } s := strings.Join([]string{`&WrappedKey{`, - `Key:` + fmt.Sprintf("%v", this.Key) + `,`, + `DKey:` + fmt.Sprintf("%v", this.DKey) + `,`, `}`, }, "") return s @@ -628,9 +519,9 @@ func (m *Header) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SenderPk", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SenderSign", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowHdr @@ -640,23 +531,21 @@ func (m *Header) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + byteLen |= (int(b) & 0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthHdr } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex > l { return io.ErrUnexpectedEOF } - if m.SenderPk == nil { - m.SenderPk = &Sender{} - } - if err := m.SenderPk.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.SenderSign = append(m.SenderSign[:0], dAtA[iNdEx:postIndex]...) + if m.SenderSign == nil { + m.SenderSign = []byte{} } iNdEx = postIndex case 5: @@ -711,87 +600,6 @@ func (m *Header) Unmarshal(dAtA []byte) error { } return nil } -func (m *Sender) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowHdr - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: sender: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: sender: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Pk", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowHdr - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthHdr - } - postIndex := iNdEx + byteLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Pk = append(m.Pk[:0], dAtA[iNdEx:postIndex]...) - if m.Pk == nil { - m.Pk = []byte{} - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipHdr(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthHdr - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *WrappedKey) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -821,9 +629,9 @@ func (m *WrappedKey) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: wrapped_key: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 2: + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DKey", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -847,9 +655,9 @@ func (m *WrappedKey) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) - if m.Key == nil { - m.Key = []byte{} + m.DKey = append(m.DKey[:0], dAtA[iNdEx:postIndex]...) + if m.DKey == nil { + m.DKey = []byte{} } iNdEx = postIndex default: @@ -981,22 +789,21 @@ var ( func init() { proto.RegisterFile("internal/pb/hdr.proto", fileDescriptorHdr) } var fileDescriptorHdr = []byte{ - // 265 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x4c, 0x90, 0x4f, 0x4a, 0xc3, 0x50, - 0x10, 0xc6, 0x33, 0x69, 0x0d, 0x76, 0xe2, 0x3f, 0x1e, 0x08, 0x6f, 0xe3, 0x18, 0xe2, 0xc2, 0x2c, - 0x24, 0x85, 0x7a, 0x03, 0x4f, 0x20, 0xf1, 0x00, 0x21, 0x31, 0x03, 0x09, 0xaf, 0xa4, 0x8f, 0x97, - 0x88, 0xa4, 0x2b, 0x8f, 0xe0, 0xd6, 0x1b, 0x78, 0x14, 0x97, 0x5d, 0xba, 0x34, 0xcf, 0x8d, 0xcb, - 0x1e, 0x41, 0x9a, 0x54, 0x70, 0x35, 0x1f, 0xbf, 0xf9, 0x86, 0x6f, 0xf8, 0xf0, 0xbc, 0xaa, 0x5b, - 0x36, 0x75, 0xb6, 0x9c, 0xeb, 0x7c, 0x5e, 0x16, 0x26, 0xd6, 0x66, 0xd5, 0xae, 0x84, 0xab, 0xf3, - 0xf0, 0x0d, 0xd0, 0x2b, 0x39, 0x2b, 0xd8, 0x88, 0x0b, 0xc4, 0xc7, 0xf2, 0xa9, 0x56, 0x69, 0x53, - 0xad, 0x59, 0x42, 0x00, 0xd1, 0x71, 0x32, 0x1b, 0xc8, 0x43, 0xb5, 0x66, 0x21, 0x70, 0xda, 0x64, - 0xcb, 0x56, 0xba, 0x01, 0x44, 0x47, 0xc9, 0xa0, 0xc5, 0x09, 0xba, 0x5a, 0xc9, 0xc9, 0x40, 0x5c, - 0xad, 0xc4, 0x35, 0xce, 0x1a, 0xae, 0x0b, 0x36, 0xa9, 0x56, 0x72, 0x1a, 0x40, 0xe4, 0x2f, 0x30, - 0xd6, 0x79, 0x3c, 0xc2, 0xe4, 0x70, 0x9c, 0xf7, 0x4a, 0x5c, 0xe1, 0x54, 0x71, 0xd7, 0xc8, 0x83, - 0x60, 0x12, 0xf9, 0x8b, 0xd3, 0x9d, 0xe7, 0xd9, 0x64, 0x5a, 0x73, 0x91, 0x2a, 0xee, 0x92, 0x61, - 0x19, 0x4a, 0xf4, 0xc6, 0x83, 0x7d, 0x0e, 0xfc, 0xe5, 0x84, 0x97, 0xe8, 0xff, 0xb3, 0x8b, 0x33, - 0x9c, 0x28, 0xee, 0xf6, 0x9f, 0xed, 0xe4, 0xdd, 0xcd, 0xa6, 0x27, 0xe7, 0xb3, 0x27, 0x67, 0xdb, - 0x13, 0xbc, 0x58, 0x82, 0x77, 0x4b, 0xf0, 0x61, 0x09, 0x36, 0x96, 0xe0, 0xcb, 0x12, 0xfc, 0x58, - 0x72, 0xb6, 0x96, 0xe0, 0xf5, 0x9b, 0x9c, 0xdc, 0x1b, 0xfa, 0xb8, 0xfd, 0x0d, 0x00, 0x00, 0xff, - 0xff, 0x7f, 0xa8, 0x12, 0x55, 0x28, 0x01, 0x00, 0x00, + // 252 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x4c, 0xcf, 0x31, 0x4e, 0xeb, 0x40, + 0x10, 0xc6, 0x71, 0x8f, 0xe3, 0x44, 0x7a, 0xe3, 0x3c, 0x90, 0x16, 0x21, 0xb9, 0x61, 0xb0, 0x4c, + 0xe3, 0x02, 0x39, 0x12, 0xdc, 0x80, 0x96, 0xce, 0x39, 0x80, 0x65, 0xe3, 0x51, 0x6c, 0x6d, 0xb4, + 0x59, 0xed, 0x1a, 0x21, 0xa7, 0xe2, 0x08, 0x70, 0x0b, 0x8e, 0x42, 0x99, 0x92, 0x12, 0x2f, 0x0d, + 0x65, 0x8e, 0x80, 0xb4, 0x34, 0x74, 0x9f, 0x7e, 0xff, 0x66, 0x06, 0xcf, 0x7b, 0x35, 0xb0, 0x51, + 0xf5, 0x76, 0xa5, 0x9b, 0x55, 0xd7, 0x9a, 0x42, 0x9b, 0xdd, 0xb0, 0x13, 0xa1, 0x6e, 0xb2, 0x57, + 0xc0, 0x45, 0xc7, 0x75, 0xcb, 0x46, 0x5c, 0x20, 0x3e, 0x74, 0x8f, 0x4a, 0x56, 0xb6, 0xdf, 0x73, + 0x02, 0x29, 0xe4, 0xff, 0xcb, 0x7f, 0x5e, 0xd6, 0xfd, 0x9e, 0x85, 0xc0, 0xc8, 0xd6, 0xdb, 0x21, + 0x09, 0x53, 0xc8, 0x97, 0xa5, 0xdf, 0xe2, 0x04, 0x43, 0x2d, 0x93, 0x99, 0x97, 0x50, 0x4b, 0x71, + 0x89, 0xb1, 0x65, 0xd5, 0xb2, 0xa9, 0x6c, 0xbf, 0x51, 0x49, 0xe4, 0x03, 0xfe, 0xd2, 0xba, 0xdf, + 0x28, 0x71, 0x85, 0x91, 0xe4, 0xd1, 0x26, 0xf3, 0x74, 0x96, 0xc7, 0x37, 0xa7, 0x85, 0x6e, 0x8a, + 0x27, 0x53, 0x6b, 0xcd, 0x6d, 0x25, 0x79, 0x2c, 0x7d, 0xcc, 0x32, 0x8c, 0xff, 0xa0, 0x38, 0xc3, + 0xb9, 0x1f, 0xfe, 0xa4, 0x65, 0x19, 0xb5, 0xf7, 0x3c, 0xde, 0x5d, 0x1f, 0x26, 0x0a, 0x3e, 0x26, + 0x0a, 0x8e, 0x13, 0xc1, 0xb3, 0x23, 0x78, 0x73, 0x04, 0xef, 0x8e, 0xe0, 0xe0, 0x08, 0x3e, 0x1d, + 0xc1, 0xb7, 0xa3, 0xe0, 0xe8, 0x08, 0x5e, 0xbe, 0x28, 0x68, 0x16, 0xfe, 0xe1, 0xdb, 0x9f, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x88, 0x3d, 0x22, 0x56, 0x09, 0x01, 0x00, 0x00, } diff --git a/internal/pb/hdr.proto b/internal/pb/hdr.proto index d01cecb..21122c2 100644 --- a/internal/pb/hdr.proto +++ b/internal/pb/hdr.proto @@ -16,18 +16,11 @@ package pb; * protobuf format before writing to disk. */ message header { - uint32 chunk_size = 1; - bytes salt = 2; - bytes pk = 3; // sender's ephemeral curve PK - sender sender_pk = 4; // sender's encrypted ed25519 PK - repeated wrapped_key keys = 5; -} - -/* - * Sender info is wrapped using the data encryption key - */ -message sender { - bytes pk = 1; + uint32 chunk_size = 1; // encryption block size + bytes salt = 2; // master salt (nonces are derived from this) + bytes pk = 3; // ephemeral curve PK + bytes sender_sign = 4; // signature block of sender + repeated wrapped_key keys = 5; // list of wrapped receiver blocks } /* @@ -35,5 +28,5 @@ message sender { * key. WrappedKey describes such a wrapped key. */ message wrapped_key { - bytes key = 2; + bytes d_key = 1; // encrypted data key } diff --git a/internal/pb/wrap.go b/internal/pb/wrap.go deleted file mode 100644 index 9471e68..0000000 --- a/internal/pb/wrap.go +++ /dev/null @@ -1,97 +0,0 @@ -// wrap.go - wrap keys and sender as needed -// -// (c) 2016 Sudhi Herle -// -// Licensing Terms: GPLv2 -// -// If you need a commercial license for this work, please contact -// the author. -// -// This software does not come with any express or implied -// warranty; it is provided "as is". No claim is made to its -// suitability for any purpose. -// - -package pb - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/rand" - "crypto/sha256" - "fmt" - "io" -) - -const ( - WrapReceiverNonce = "Receiver PK" - WrapSenderNonce = "Sender PK" -) - -// Wrap sender's PK with the data encryption key -func WrapSenderPK(pk []byte, k, salt []byte) ([]byte, error) { - aes, err := aes.NewCipher(k) - if err != nil { - return nil, fmt.Errorf("wrap: %s", err) - } - - ae, err := cipher.NewGCM(aes) - if err != nil { - return nil, fmt.Errorf("wrap: %s", err) - } - - nonce := MakeNonce([]byte(WrapSenderNonce), salt) - buf := make([]byte, ae.Overhead()+len(pk)) - out := ae.Seal(buf[:0], nonce[:ae.NonceSize()], pk, nil) - return out, nil -} - -// Given a wrapped PK of sender 's', unwrap it using the given key and salt -func (s *Sender) UnwrapPK(k, salt []byte) ([]byte, error) { - aes, err := aes.NewCipher(k) - if err != nil { - return nil, fmt.Errorf("uwrap-sender: %s", err) - } - - ae, err := cipher.NewGCM(aes) - if err != nil { - return nil, fmt.Errorf("unwrap-sender: %s", err) - } - - nonce := MakeNonce([]byte(WrapSenderNonce), salt) - want := 32 + ae.Overhead() - if len(s.Pk) != want { - return nil, fmt.Errorf("unwrap-sender: incorrect decrypt bytes (need %d, saw %d)", want, 32) - } - - out := make([]byte, 32) - pk, err := ae.Open(out[:0], nonce[:ae.NonceSize()], s.Pk, nil) - if err != nil { - return nil, fmt.Errorf("unwrap-sender: %s", err) - } - - return pk, nil -} - -func MakeNonce(v ...[]byte) []byte { - h := sha256.New() - for _, x := range v { - h.Write(x) - } - return h.Sum(nil)[:] -} - -func Clamp(k []byte) []byte { - k[0] &= 248 - k[31] &= 127 - k[31] |= 64 - return k -} - -func Randread(b []byte) []byte { - _, err := io.ReadFull(rand.Reader, b) - if err != nil { - panic(fmt.Sprintf("can't read %d bytes of random data: %s", len(b), err)) - } - return b -} diff --git a/sign/encrypt.go b/sign/encrypt.go index f5aa0af..a65a924 100644 --- a/sign/encrypt.go +++ b/sign/encrypt.go @@ -56,6 +56,7 @@ import ( "bytes" "crypto/aes" "crypto/cipher" + "crypto/ed25519" "crypto/sha256" "crypto/sha512" "crypto/subtle" @@ -76,8 +77,12 @@ const ( _Magic = "SigTool" _MagicLen = len(_Magic) - _AEADNonceLen = 32 + _AEADNonceLen = 16 _FixedHdrLen = _MagicLen + 1 + 4 + + _WrapReceiverNonce = "Receiver Key Nonce" + _WrapSenderNonce = "Sender Sig Nonce" + _EncryptNonce = "Encrypt Nonce" ) // Encryptor holds the encryption context @@ -87,9 +92,8 @@ type Encryptor struct { ae cipher.AEAD - // sender ephemeral curve 25519 SK - // the corresponding PK is in Header above - senderSK []byte + // ephemeral key + encSK []byte started bool @@ -98,9 +102,8 @@ type Encryptor struct { stream bool } -// Create a new Encryption context and use the optional private key 'sk' for -// signing any recipient keys. If 'sk' is nil, then ephmeral Curve25519 keys -// are generated and used with recipient's public key. +// Create a new Encryption context for encrypting blocks of size 'blksize'. +// If 'sk' is not nil, authenticate the sender to each receiver. func NewEncryptor(sk *PrivateKey, blksize uint64) (*Encryptor, error) { var blksz uint32 @@ -113,7 +116,8 @@ func NewEncryptor(sk *PrivateKey, blksize uint64) (*Encryptor, error) { blksz = uint32(blksize) } - csk, cpk, err := newSender() + // generate ephemeral Curve25519 keys + esk, epk, err := newSender() if err != nil { return nil, fmt.Errorf("encrypt: %s", err) } @@ -121,33 +125,39 @@ func NewEncryptor(sk *PrivateKey, blksize uint64) (*Encryptor, error) { key := make([]byte, 32) salt := make([]byte, _AEADNonceLen) - pb.Randread(key) - pb.Randread(salt) + randRead(key) + randRead(salt) - // if sender has provided their identity to authenticate, we will use their PK - senderPK := cpk + // if sender has provided their identity to authenticate, we sign the data-enc key + // and encrypt the signature. At no point will we send the sender's identity. + var senderSig []byte if sk != nil { - epk := sk.PublicKey() - senderPK = epk.toCurve25519PK() + sig, err := sk.SignMessage(key, "") + if err != nil { + return nil, fmt.Errorf("encrypt: can't sign: %s", err) + } + + senderSig = sig.Sig + } else { + var zero [ed25519.SignatureSize]byte + senderSig = zero[:] } - wPk, err := pb.WrapSenderPK(senderPK, key, salt) + wSig, err := wrapSenderSig(senderSig, key, salt) if err != nil { return nil, fmt.Errorf("encrypt: %s", err) } e := &Encryptor{ Header: pb.Header{ - ChunkSize: blksz, - Salt: salt, - Pk: cpk, - SenderPk: &pb.Sender{ - Pk: wPk, - }, + ChunkSize: blksz, + Salt: salt, + Pk: epk, + SenderSign: wSig, }, - key: key, - senderSK: csk, + key: key, + encSK: esk, } return e, nil @@ -159,7 +169,7 @@ func (e *Encryptor) AddRecipient(pk *PublicKey) error { return fmt.Errorf("encrypt: can't add new recipient after encryption has started") } - w, err := wrapKey(pk, e.key, e.senderSK, e.Salt) + w, err := e.wrapKey(pk) if err == nil { e.Keys = append(e.Keys, w) } @@ -241,7 +251,7 @@ func (e *Encryptor) start(wr io.Writer) error { // we mix the header checksum to create the encryption key h = sha256.New() - h.Write([]byte("Encrypt Nonce")) + h.Write([]byte(_EncryptNonce)) h.Write(e.key) h.Write(sumHdr) key := h.Sum(nil) @@ -286,7 +296,7 @@ func fullwrite(buf []byte, wr io.Writer) error { // additional data in the AEAD construction. func (e *Encryptor) encrypt(buf []byte, wr io.Writer, i uint32, eof bool) error { var b [8]byte - var noncebuf [32]byte + var nonceb [32]byte var z uint32 = uint32(len(buf)) // mark last block @@ -300,7 +310,7 @@ func (e *Encryptor) encrypt(buf []byte, wr io.Writer, i uint32, eof bool) error h := sha256.New() h.Write(e.Salt) h.Write(b[:]) - nonce := h.Sum(noncebuf[:0]) + nonce := h.Sum(nonceb[:0])[:e.ae.NonceSize()] copy(e.buf[:4], b[:4]) cbuf := e.buf[4:] @@ -324,6 +334,9 @@ type Decryptor struct { buf []byte hdrsum []byte + // flag set to true if sender signed the key + auth bool + // Decrypted key key []byte eof bool @@ -401,7 +414,7 @@ func NewDecryptor(rd io.Reader) (*Decryptor, error) { // sanity check on the wrapped keys for i, w := range d.Keys { - if len(w.Key) <= 32+12 { + if len(w.DKey) <= 32 { return nil, fmt.Errorf("decrypt: wrapped key %d: wrong-size encrypted key", i) } } @@ -416,7 +429,7 @@ func (d *Decryptor) SetPrivateKey(sk *PrivateKey, senderPk *PublicKey) error { var key []byte for i, w := range d.Keys { - key, err = unwrapKey(w.Key, sk, d.Pk, d.Salt) + key, err = d.unwrapKey(w, sk) if err != nil { return fmt.Errorf("decrypt: can't unwrap key %d: %s", i, err) } @@ -428,25 +441,15 @@ func (d *Decryptor) SetPrivateKey(sk *PrivateKey, senderPk *PublicKey) error { return fmt.Errorf("decrypt: wrong key") havekey: - if senderPk != nil { - hpk, err := d.SenderPk.UnwrapPK(key, d.Salt) - if err != nil { - return fmt.Errorf("decrypt: can't unwrap sender PK: %s", err) - } - - cpk := senderPk.toCurve25519PK() - if subtle.ConstantTimeCompare(cpk, hpk) == 0 { - return fmt.Errorf("decrypt: sender verification failed") - } + if err := d.verifySender(key, sk, senderPk); err != nil { + return fmt.Errorf("decrypt: %s", err) } - // XXX do we need to verify d.Header.Sender.Key vs. d.Header.PK? - d.key = key // we mix the header checksum into the key h := sha256.New() - h.Write([]byte("Encrypt Nonce")) + h.Write([]byte(_EncryptNonce)) h.Write(d.key) h.Write(d.hdrsum) key = h.Sum(nil) @@ -464,72 +467,10 @@ havekey: return nil } -// Wrap data encryption key 'k' with the sender's PK and our ephemeral curve SK -func wrapKey(pk *PublicKey, k, ourSK, salt []byte) (*pb.WrappedKey, error) { - shared, err := curve25519.X25519(ourSK, pk.toCurve25519PK()) - if err != nil { - return nil, fmt.Errorf("wrap: %s", err) - } - - aes, err := aes.NewCipher(shared) - if err != nil { - return nil, fmt.Errorf("wrap: %s", err) - } - - ae, err := cipher.NewGCM(aes) - if err != nil { - return nil, fmt.Errorf("wrap: %s", err) - } - - tagsize := ae.Overhead() - - nonce := pb.MakeNonce([]byte(pb.WrapReceiverNonce), salt) - buf := make([]byte, tagsize+len(shared)) - out := ae.Seal(buf[:0], nonce[:ae.NonceSize()], k, pk.Pk) - return &pb.WrappedKey{ - Key: out, - }, nil -} - -// Unwrap a wrapped key using the receivers Ed25519 secret key 'sk' and -// senders ephemeral PublicKey -func unwrapKey(wkey []byte, sk *PrivateKey, curvePK, salt []byte) ([]byte, error) { - ourSK := sk.toCurve25519SK() - shared, err := curve25519.X25519(ourSK, curvePK) - if err != nil { - return nil, fmt.Errorf("unwrap: %s", err) - } - - aes, err := aes.NewCipher(shared) - if err != nil { - return nil, fmt.Errorf("unwrap: %s", err) - } - - ae, err := cipher.NewGCM(aes) - if err != nil { - return nil, fmt.Errorf("unwrap: %s", err) - } - - want := 32 + ae.Overhead() - if len(wkey) != want { - return nil, fmt.Errorf("unwrap: incorrect decrypt bytes (need %d, saw %d)", want, len(wkey)) - } - - nonce := pb.MakeNonce([]byte(pb.WrapReceiverNonce), salt) - pk := sk.PublicKey() - out := make([]byte, 32) - c, err := ae.Open(out[:0], nonce[:ae.NonceSize()], wkey, pk.Pk) - - // we indicate incorrect receiver SK by returning a nil key - if err != nil { - return nil, nil - } - return c, nil -} - -// Return a list of Wrapped keys in the encrypted file header -func (d *Decryptor) WrappedKeys() []*pb.WrappedKey { - return d.Keys +// AuthenticatedSender returns true if the sender authenticated themselves +// (the data-encryption key is signed). +func (d *Decryptor) AuthenticatedSender() bool { + return d.auth } // Decrypt the file and write to 'wr' @@ -567,6 +508,143 @@ func (d *Decryptor) Decrypt(wr io.Writer) error { return nil } +// Wrap sender's signature of the encryption key +func wrapSenderSig(sig []byte, key, salt []byte) ([]byte, error) { + aes, err := aes.NewCipher(key) + if err != nil { + return nil, fmt.Errorf("wrap: %s", err) + } + + ae, err := cipher.NewGCM(aes) + if err != nil { + return nil, fmt.Errorf("wrap: %s", err) + } + + tagsize := ae.Overhead() + nonceSize := ae.NonceSize() + + nonce := makeNonce([]byte(_WrapSenderNonce), salt)[:nonceSize] + esig := make([]byte, tagsize+len(sig)) + + return ae.Seal(esig[:0], nonce, sig, nil), nil +} + +// unwrap sender's signature using 'key' and extract the signature +// Optionally, verify the signature using the sender's PK (if provided). +func (d *Decryptor) verifySender(key []byte, sk *PrivateKey, senderPK *PublicKey) error { + aes, err := aes.NewCipher(key) + if err != nil { + return fmt.Errorf("unwrap: %s", err) + } + + ae, err := cipher.NewGCM(aes) + if err != nil { + return fmt.Errorf("unwrap: %s", err) + } + + nonceSize := ae.NonceSize() + nonce := makeNonce([]byte(_WrapSenderNonce), d.Salt)[:nonceSize] + sig := make([]byte, ed25519.SignatureSize) + sig, err = ae.Open(sig[:0], nonce, d.SenderSign, nil) + if err != nil { + return fmt.Errorf("unwrap: can't open sender info: %s", err) + } + + var zero [ed25519.SignatureSize]byte + + // Did the sender actually sign anything? + if subtle.ConstantTimeCompare(zero[:], sig) == 0 { + d.auth = true + + if senderPK != nil { + ss := &Signature{ + Sig: sig, + } + + ok := senderPK.VerifyMessage(key, ss) + if !ok { + return fmt.Errorf("unwrap: sender verification failed") + } + } + } + return nil +} + +// Wrap data encryption key 'k' with the sender's PK and our ephemeral curve SK +// basically, we do two scalarmults: +// a) Ephemeral encryption/decryption SK x receiver PK +// b) Sender's SK x receiver PK +func (e *Encryptor) wrapKey(pk *PublicKey) (*pb.WrappedKey, error) { + rxPK := pk.toCurve25519PK() + dkek, err := curve25519.X25519(e.encSK, rxPK) + if err != nil { + return nil, fmt.Errorf("wrap: %s", err) + } + + aes, err := aes.NewCipher(dkek) + if err != nil { + return nil, fmt.Errorf("wrap: %s", err) + } + + ae, err := cipher.NewGCM(aes) + if err != nil { + return nil, fmt.Errorf("wrap: %s", err) + } + + tagsize := ae.Overhead() + nonceSize := ae.NonceSize() + + nonceR := makeNonce([]byte(_WrapReceiverNonce), e.Salt)[:nonceSize] + ekey := make([]byte, tagsize+len(e.key)) + + w := &pb.WrappedKey{ + DKey: ae.Seal(ekey[:0], nonceR, e.key, pk.Pk), + } + + return w, nil +} + +// Unwrap a wrapped key using the receivers Ed25519 secret key 'sk' and +// senders ephemeral PublicKey +func (d *Decryptor) unwrapKey(w *pb.WrappedKey, sk *PrivateKey) ([]byte, error) { + ourSK := sk.toCurve25519SK() + dkek, err := curve25519.X25519(ourSK, d.Pk) + if err != nil { + return nil, fmt.Errorf("unwrap: %s", err) + } + + aes, err := aes.NewCipher(dkek) + if err != nil { + return nil, fmt.Errorf("unwrap: %s", err) + } + + ae, err := cipher.NewGCM(aes) + if err != nil { + return nil, fmt.Errorf("unwrap: %s", err) + } + + // 32 == AES-256 key size + want := 32 + ae.Overhead() + if len(w.DKey) != want { + return nil, fmt.Errorf("unwrap: incorrect decrypt bytes (need %d, saw %d)", want, len(w.DKey)) + } + + nonceSize := ae.NonceSize() + + nonceR := makeNonce([]byte(_WrapReceiverNonce), d.Salt)[:nonceSize] + pk := sk.PublicKey() + + dkey := make([]byte, 32) // decrypted data decryption key + + // we indicate incorrect receiver SK by returning a nil key + dkey, err = ae.Open(dkey[:0], nonceR, w.DKey, pk.Pk) + if err != nil { + return nil, nil + } + + return dkey, nil +} + // Decrypt exactly one chunk of data func (d *Decryptor) decrypt(i uint32) ([]byte, bool, error) { var b [8]byte @@ -605,7 +683,7 @@ func (d *Decryptor) decrypt(i uint32) ([]byte, bool, error) { h := sha256.New() h.Write(d.Salt) h.Write(b[:]) - nonce := h.Sum(nonceb[:0]) + nonce := h.Sum(nonceb[:0])[:d.ae.NonceSize()] z := m + ovh n, err = io.ReadFull(d.rd, d.buf[:z]) @@ -632,9 +710,19 @@ func expand(shared, pk []byte) ([]byte, error) { func newSender() (sk, pk []byte, err error) { var csk [32]byte - pb.Randread(csk[:]) - pb.Clamp(csk[:]) + randRead(csk[:]) + clamp(csk[:]) pk, err = curve25519.X25519(csk[:], curve25519.Basepoint) sk = csk[:] return } + +func makeNonce(v ...[]byte) []byte { + h := sha256.New() + for _, x := range v { + h.Write(x) + } + return h.Sum(nil)[:] +} + +// EOF diff --git a/sign/keys.go b/sign/keys.go index 390459e..143d19b 100644 --- a/sign/keys.go +++ b/sign/keys.go @@ -28,6 +28,7 @@ import ( "encoding/binary" "fmt" "hash" + "io" "io/ioutil" "math/big" "os" @@ -37,7 +38,6 @@ import ( "gopkg.in/yaml.v2" "github.com/opencoff/go-utils" - "github.com/opencoff/sigtool/internal/pb" ) // Private Ed25519 key @@ -70,12 +70,6 @@ type Keypair struct { Pub PublicKey } -// An Ed25519 Signature -type Signature struct { - Sig []byte // Ed25519 sig bytes - pkhash []byte // [0:16] SHA256 hash of public key needed for verification -} - // Length of Ed25519 Public Key Hash const PKHashLength = 16 @@ -349,7 +343,7 @@ func (sk *PrivateKey) serialize(fn, comment string, getpw func() ([]byte, error) pass := sha512.Sum512(pw) salt := make([]byte, 32) - pb.Randread(salt) + randRead(salt) // "32" == Length of AES-256 key key, err := scrypt.Key(pass[:], salt, _N, _r, _p, 32) @@ -544,5 +538,13 @@ func clamp(k []byte) []byte { return k } +func randRead(b []byte) []byte { + _, err := io.ReadFull(rand.Reader, b) + if err != nil { + panic(fmt.Sprintf("can't read %d bytes of random data: %s", len(b), err)) + } + return b +} + // EOF // vim: noexpandtab:ts=8:sw=8:tw=92: diff --git a/sign/sign.go b/sign/sign.go index a17ba52..c7b0a8a 100644 --- a/sign/sign.go +++ b/sign/sign.go @@ -30,6 +30,12 @@ import ( "gopkg.in/yaml.v2" ) +// An Ed25519 Signature +type Signature struct { + Sig []byte // Ed25519 sig bytes + pkhash []byte // [0:16] SHA256 hash of public key needed for verification +} + // Sign a prehashed Message; return the signature as opaque bytes // Signature is an YAML file: // Comment: source file path @@ -147,19 +153,19 @@ func (pk *PublicKey) VerifyFile(fn string, sig *Signature) (bool, error) { return false, err } - return pk.VerifyMessage(ck, sig) + return pk.VerifyMessage(ck, sig), nil } // Verify a signature 'sig' for a pre-calculated checksum 'ck' against public key 'pk' // Return True if signature matches, False otherwise -func (pk *PublicKey) VerifyMessage(ck []byte, sig *Signature) (bool, error) { +func (pk *PublicKey) VerifyMessage(ck []byte, sig *Signature) bool { h := sha512.New() h.Write([]byte("sigtool signed message")) h.Write(ck) ck = h.Sum(nil)[:] x := Ed.PublicKey(pk.Pk) - return Ed.Verify(x, ck, sig.Sig), nil + return Ed.Verify(x, ck, sig.Sig) } // vim: noexpandtab:ts=8:sw=8:tw=92: diff --git a/sign/sign_test.go b/sign/sign_test.go index 14106c7..b794657 100644 --- a/sign/sign_test.go +++ b/sign/sign_test.go @@ -19,8 +19,6 @@ import ( "os" "path" "testing" - - "github.com/opencoff/sigtool/internal/pb" ) // Return a temp dir in a temp-dir @@ -30,7 +28,7 @@ func tempdir(t *testing.T) string { var b [10]byte dn := os.TempDir() - pb.Randread(b[:]) + randRead(b[:]) tmp := path.Join(dn, fmt.Sprintf("%x", b[:])) err := os.MkdirAll(tmp, 0755) @@ -137,7 +135,7 @@ func TestSignRandBuf(t *testing.T) { var ck [64]byte // simulates sha512 sum - pb.Randread(ck[:]) + randRead(ck[:]) pk := &kp.Pub sk := &kp.Sec @@ -150,17 +148,15 @@ func TestSignRandBuf(t *testing.T) { assert(ss.IsPKMatch(pk), "pk match fail") // Corrupt the pkhash and see - pb.Randread(ss.pkhash) + randRead(ss.pkhash) assert(!ss.IsPKMatch(pk), "corrupt pk match fail") // Incorrect checksum == should fail verification - ok, err := pk.VerifyMessage(ck[:16], ss) - assert(err == nil, "bad ck verify err fail") + ok := pk.VerifyMessage(ck[:16], ss) assert(!ok, "bad ck verify fail") // proper checksum == should work - ok, err = pk.VerifyMessage(ck[:], ss) - assert(err == nil, "verify err") + ok = pk.VerifyMessage(ck[:], ss) assert(ok, "verify fail") // Now sign a file @@ -187,7 +183,7 @@ func TestSignRandBuf(t *testing.T) { assert(err == nil, "file.dat creat file") for i := 0; i < 8; i++ { - pb.Randread(buf[:]) + randRead(buf[:]) n, err := fd.Write(buf[:]) assert(err == nil, fmt.Sprintf("file.dat write fail: %s", err)) assert(n == 8192, fmt.Sprintf("file.dat i/o fail: exp 8192 saw %v", n)) @@ -288,7 +284,7 @@ func benchVerify(b *testing.B, buf []byte, sig *Signature, pk *PublicKey) { func randbuf(sz uint) []byte { b := make([]byte, sz) - pb.Randread(b) + randRead(b) return b } diff --git a/version b/version index 3eefcb9..9084fa2 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.0.0 +1.1.0