1// Copyright 2020 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14// 15//////////////////////////////////////////////////////////////////////////////// 16 17package subtle_test 18 19import ( 20 "bytes" 21 "encoding/hex" 22 "fmt" 23 "io" 24 25 "github.com/google/tink/go/tink" 26) 27 28var ( 29 ikm = []byte{ 30 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 31 0xc, 0xd, 0xe, 0xf, 0x0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 32 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 33 } 34 aad = []byte{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff} 35) 36 37// encrypt generates a random plaintext of size plaintextSize and encrypts it 38// using the cipher. Upon success this function returns the actual plaintext 39// and ciphertext bytes. 40func encrypt(cipher tink.StreamingAEAD, aad []byte, plaintextSize int) ([]byte, []byte, error) { 41 pt := make([]byte, plaintextSize) 42 for i := range pt { 43 pt[i] = byte(i % 253) 44 } 45 46 ctBuf := &bytes.Buffer{} 47 w, err := cipher.NewEncryptingWriter(ctBuf, aad) 48 if err != nil { 49 return nil, nil, fmt.Errorf("cannot create an encrypt writer: %v", err) 50 } 51 n, err := w.Write(pt) 52 if err != nil { 53 return nil, nil, fmt.Errorf("error writing to an encrypt writer: %v", err) 54 } 55 if n != len(pt) { 56 return nil, nil, fmt.Errorf("unexpected number of bytes written. Got=%d;want=%d", n, len(pt)) 57 } 58 if err := w.Close(); err != nil { 59 return nil, nil, fmt.Errorf("error closing writer: %v", err) 60 } 61 return pt, ctBuf.Bytes(), err 62} 63 64// decrypt decrypts ciphertext ct using the cipher and validates that it's the 65// same as the original plaintext pt. 66func decrypt(cipher tink.StreamingAEAD, aad, pt, ct []byte, chunkSize int) error { 67 r, err := cipher.NewDecryptingReader(bytes.NewBuffer(ct), aad) 68 if err != nil { 69 return fmt.Errorf("cannot create an encrypt reader: %v", err) 70 } 71 72 var ( 73 chunk = make([]byte, chunkSize) 74 decrypted = 0 75 eof = false 76 ) 77 for !eof { 78 n, err := r.Read(chunk) 79 if err != nil && err != io.EOF { 80 return fmt.Errorf("error reading chunk: %v", err) 81 } 82 eof = err == io.EOF 83 got := chunk[:n] 84 want := pt[decrypted : decrypted+n] 85 if !bytes.Equal(got, want) { 86 return fmt.Errorf("decrypted data doesn't match. Got=%s;want=%s", hex.EncodeToString(got), hex.EncodeToString(want)) 87 } 88 decrypted += n 89 } 90 if decrypted != len(pt) { 91 return fmt.Errorf("number of decrypted bytes doesn't match. Got=%d;want=%d", decrypted, len(pt)) 92 } 93 return nil 94} 95 96func segmentPos(segmentSize, firstSegmentOffset, headerLen, segmentNr int) (int, int) { 97 start := segmentSize * segmentNr 98 end := start + segmentSize 99 100 firstSegmentDiff := firstSegmentOffset + headerLen 101 if start > 0 { 102 start -= firstSegmentDiff 103 } 104 end -= firstSegmentDiff 105 return start + headerLen, end + headerLen 106} 107