1*e7b1675dSTing-Kang Chang// Copyright 2020 Google LLC 2*e7b1675dSTing-Kang Chang// 3*e7b1675dSTing-Kang Chang// Licensed under the Apache License, Version 2.0 (the "License"); 4*e7b1675dSTing-Kang Chang// you may not use this file except in compliance with the License. 5*e7b1675dSTing-Kang Chang// You may obtain a copy of the License at 6*e7b1675dSTing-Kang Chang// 7*e7b1675dSTing-Kang Chang// http://www.apache.org/licenses/LICENSE-2.0 8*e7b1675dSTing-Kang Chang// 9*e7b1675dSTing-Kang Chang// Unless required by applicable law or agreed to in writing, software 10*e7b1675dSTing-Kang Chang// distributed under the License is distributed on an "AS IS" BASIS, 11*e7b1675dSTing-Kang Chang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*e7b1675dSTing-Kang Chang// See the License for the specific language governing permissions and 13*e7b1675dSTing-Kang Chang// limitations under the License. 14*e7b1675dSTing-Kang Chang// 15*e7b1675dSTing-Kang Chang//////////////////////////////////////////////////////////////////////////////// 16*e7b1675dSTing-Kang Chang 17*e7b1675dSTing-Kang Changpackage streamingaead_test 18*e7b1675dSTing-Kang Chang 19*e7b1675dSTing-Kang Chang// [START streaming-aead-example] 20*e7b1675dSTing-Kang Chang 21*e7b1675dSTing-Kang Changimport ( 22*e7b1675dSTing-Kang Chang "bytes" 23*e7b1675dSTing-Kang Chang "fmt" 24*e7b1675dSTing-Kang Chang "io" 25*e7b1675dSTing-Kang Chang "log" 26*e7b1675dSTing-Kang Chang "os" 27*e7b1675dSTing-Kang Chang "path/filepath" 28*e7b1675dSTing-Kang Chang 29*e7b1675dSTing-Kang Chang "github.com/google/tink/go/insecurecleartextkeyset" 30*e7b1675dSTing-Kang Chang "github.com/google/tink/go/keyset" 31*e7b1675dSTing-Kang Chang "github.com/google/tink/go/streamingaead" 32*e7b1675dSTing-Kang Chang) 33*e7b1675dSTing-Kang Chang 34*e7b1675dSTing-Kang Changfunc Example() { 35*e7b1675dSTing-Kang Chang // A keyset created with "tinkey create-keyset --key-template=AES256_CTR_HMAC_SHA256_1MB". Note 36*e7b1675dSTing-Kang Chang // that this keyset has the secret key information in cleartext. 37*e7b1675dSTing-Kang Chang jsonKeyset := `{ 38*e7b1675dSTing-Kang Chang "primaryKeyId": 1720777699, 39*e7b1675dSTing-Kang Chang "key": [{ 40*e7b1675dSTing-Kang Chang "keyData": { 41*e7b1675dSTing-Kang Chang "typeUrl": "type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey", 42*e7b1675dSTing-Kang Chang "keyMaterialType": "SYMMETRIC", 43*e7b1675dSTing-Kang Chang "value": "Eg0IgCAQIBgDIgQIAxAgGiDtesd/4gCnQdTrh+AXodwpm2b6BFJkp043n+8mqx0YGw==" 44*e7b1675dSTing-Kang Chang }, 45*e7b1675dSTing-Kang Chang "outputPrefixType": "RAW", 46*e7b1675dSTing-Kang Chang "keyId": 1720777699, 47*e7b1675dSTing-Kang Chang "status": "ENABLED" 48*e7b1675dSTing-Kang Chang }] 49*e7b1675dSTing-Kang Chang }` 50*e7b1675dSTing-Kang Chang 51*e7b1675dSTing-Kang Chang // Create a keyset handle from the cleartext keyset in the previous 52*e7b1675dSTing-Kang Chang // step. The keyset handle provides abstract access to the underlying keyset to 53*e7b1675dSTing-Kang Chang // limit the exposure of accessing the raw key material. WARNING: In practice, 54*e7b1675dSTing-Kang Chang // it is unlikely you will want to use an insecurecleartextkeyset, as it implies 55*e7b1675dSTing-Kang Chang // that your key material is passed in cleartext, which is a security risk. 56*e7b1675dSTing-Kang Chang // Consider encrypting it with a remote key in Cloud KMS, AWS KMS or HashiCorp Vault. 57*e7b1675dSTing-Kang Chang // See https://github.com/google/tink/blob/master/docs/GOLANG-HOWTO.md#storing-and-loading-existing-keysets. 58*e7b1675dSTing-Kang Chang keysetHandle, err := insecurecleartextkeyset.Read( 59*e7b1675dSTing-Kang Chang keyset.NewJSONReader(bytes.NewBufferString(jsonKeyset))) 60*e7b1675dSTing-Kang Chang if err != nil { 61*e7b1675dSTing-Kang Chang log.Fatal(err) 62*e7b1675dSTing-Kang Chang } 63*e7b1675dSTing-Kang Chang 64*e7b1675dSTing-Kang Chang // Retrieve the StreamingAEAD primitive we want to use from the keyset handle. 65*e7b1675dSTing-Kang Chang primitive, err := streamingaead.New(keysetHandle) 66*e7b1675dSTing-Kang Chang if err != nil { 67*e7b1675dSTing-Kang Chang log.Fatal(err) 68*e7b1675dSTing-Kang Chang } 69*e7b1675dSTing-Kang Chang 70*e7b1675dSTing-Kang Chang // Create a file with the plaintext. 71*e7b1675dSTing-Kang Chang dir, err := os.MkdirTemp("", "streamingaead") 72*e7b1675dSTing-Kang Chang if err != nil { 73*e7b1675dSTing-Kang Chang log.Fatal(err) 74*e7b1675dSTing-Kang Chang } 75*e7b1675dSTing-Kang Chang defer os.RemoveAll(dir) 76*e7b1675dSTing-Kang Chang plaintextPath := filepath.Join(dir, "plaintext") 77*e7b1675dSTing-Kang Chang if err := os.WriteFile(plaintextPath, []byte("this data needs to be encrypted"), 0666); err != nil { 78*e7b1675dSTing-Kang Chang log.Fatal(err) 79*e7b1675dSTing-Kang Chang } 80*e7b1675dSTing-Kang Chang plaintextFile, err := os.Open(plaintextPath) 81*e7b1675dSTing-Kang Chang if err != nil { 82*e7b1675dSTing-Kang Chang log.Fatal(err) 83*e7b1675dSTing-Kang Chang } 84*e7b1675dSTing-Kang Chang 85*e7b1675dSTing-Kang Chang // associatedData defines the context of the encryption. Here, we include the path of the 86*e7b1675dSTing-Kang Chang // plaintext file. 87*e7b1675dSTing-Kang Chang associatedData := []byte("associatedData for " + plaintextPath) 88*e7b1675dSTing-Kang Chang 89*e7b1675dSTing-Kang Chang // Encrypt the plaintext file and write the output to the ciphertext file. In this case the 90*e7b1675dSTing-Kang Chang // primary key of the keyset will be used (which is also the only key in this example). 91*e7b1675dSTing-Kang Chang ciphertextPath := filepath.Join(dir, "ciphertext") 92*e7b1675dSTing-Kang Chang ciphertextFile, err := os.Create(ciphertextPath) 93*e7b1675dSTing-Kang Chang if err != nil { 94*e7b1675dSTing-Kang Chang log.Fatal(err) 95*e7b1675dSTing-Kang Chang } 96*e7b1675dSTing-Kang Chang w, err := primitive.NewEncryptingWriter(ciphertextFile, associatedData) 97*e7b1675dSTing-Kang Chang if err != nil { 98*e7b1675dSTing-Kang Chang log.Fatal(err) 99*e7b1675dSTing-Kang Chang } 100*e7b1675dSTing-Kang Chang if _, err := io.Copy(w, plaintextFile); err != nil { 101*e7b1675dSTing-Kang Chang log.Fatal(err) 102*e7b1675dSTing-Kang Chang } 103*e7b1675dSTing-Kang Chang if err := w.Close(); err != nil { 104*e7b1675dSTing-Kang Chang log.Fatal(err) 105*e7b1675dSTing-Kang Chang } 106*e7b1675dSTing-Kang Chang if err := ciphertextFile.Close(); err != nil { 107*e7b1675dSTing-Kang Chang log.Fatal(err) 108*e7b1675dSTing-Kang Chang } 109*e7b1675dSTing-Kang Chang if err := plaintextFile.Close(); err != nil { 110*e7b1675dSTing-Kang Chang log.Fatal(err) 111*e7b1675dSTing-Kang Chang } 112*e7b1675dSTing-Kang Chang 113*e7b1675dSTing-Kang Chang // Decrypt the ciphertext file and write the output to the decrypted file. The 114*e7b1675dSTing-Kang Chang // decryption finds the correct key in the keyset and decrypts the ciphertext. 115*e7b1675dSTing-Kang Chang // If no key is found or decryption fails, it returns an error. 116*e7b1675dSTing-Kang Chang ciphertextFile, err = os.Open(ciphertextPath) 117*e7b1675dSTing-Kang Chang if err != nil { 118*e7b1675dSTing-Kang Chang log.Fatal(err) 119*e7b1675dSTing-Kang Chang } 120*e7b1675dSTing-Kang Chang decryptedPath := filepath.Join(dir, "decrypted") 121*e7b1675dSTing-Kang Chang decryptedFile, err := os.Create(decryptedPath) 122*e7b1675dSTing-Kang Chang if err != nil { 123*e7b1675dSTing-Kang Chang log.Fatal(err) 124*e7b1675dSTing-Kang Chang } 125*e7b1675dSTing-Kang Chang r, err := primitive.NewDecryptingReader(ciphertextFile, associatedData) 126*e7b1675dSTing-Kang Chang if err != nil { 127*e7b1675dSTing-Kang Chang log.Fatal(err) 128*e7b1675dSTing-Kang Chang } 129*e7b1675dSTing-Kang Chang if _, err := io.Copy(decryptedFile, r); err != nil { 130*e7b1675dSTing-Kang Chang log.Fatal(err) 131*e7b1675dSTing-Kang Chang } 132*e7b1675dSTing-Kang Chang if err := decryptedFile.Close(); err != nil { 133*e7b1675dSTing-Kang Chang log.Fatal(err) 134*e7b1675dSTing-Kang Chang } 135*e7b1675dSTing-Kang Chang if err := ciphertextFile.Close(); err != nil { 136*e7b1675dSTing-Kang Chang log.Fatal(err) 137*e7b1675dSTing-Kang Chang } 138*e7b1675dSTing-Kang Chang 139*e7b1675dSTing-Kang Chang // Print the content of the decrypted file. 140*e7b1675dSTing-Kang Chang b, err := os.ReadFile(decryptedPath) 141*e7b1675dSTing-Kang Chang if err != nil { 142*e7b1675dSTing-Kang Chang log.Fatal(err) 143*e7b1675dSTing-Kang Chang } 144*e7b1675dSTing-Kang Chang fmt.Println(string(b)) 145*e7b1675dSTing-Kang Chang // Output: this data needs to be encrypted 146*e7b1675dSTing-Kang Chang} 147*e7b1675dSTing-Kang Chang 148*e7b1675dSTing-Kang Chang// [END streaming-aead-example] 149