1// Copyright 2011 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package packet 6 7import ( 8 "bytes" 9 "crypto/cipher" 10 "io" 11 "strconv" 12 13 "golang.org/x/crypto/openpgp/errors" 14 "golang.org/x/crypto/openpgp/s2k" 15) 16 17// This is the largest session key that we'll support. Since no 512-bit cipher 18// has even been seriously used, this is comfortably large. 19const maxSessionKeySizeInBytes = 64 20 21// SymmetricKeyEncrypted represents a passphrase protected session key. See RFC 22// 4880, section 5.3. 23type SymmetricKeyEncrypted struct { 24 CipherFunc CipherFunction 25 s2k func(out, in []byte) 26 encryptedKey []byte 27} 28 29const symmetricKeyEncryptedVersion = 4 30 31func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error { 32 // RFC 4880, section 5.3. 33 var buf [2]byte 34 if _, err := readFull(r, buf[:]); err != nil { 35 return err 36 } 37 if buf[0] != symmetricKeyEncryptedVersion { 38 return errors.UnsupportedError("SymmetricKeyEncrypted version") 39 } 40 ske.CipherFunc = CipherFunction(buf[1]) 41 42 if ske.CipherFunc.KeySize() == 0 { 43 return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1]))) 44 } 45 46 var err error 47 ske.s2k, err = s2k.Parse(r) 48 if err != nil { 49 return err 50 } 51 52 encryptedKey := make([]byte, maxSessionKeySizeInBytes) 53 // The session key may follow. We just have to try and read to find 54 // out. If it exists then we limit it to maxSessionKeySizeInBytes. 55 n, err := readFull(r, encryptedKey) 56 if err != nil && err != io.ErrUnexpectedEOF { 57 return err 58 } 59 60 if n != 0 { 61 if n == maxSessionKeySizeInBytes { 62 return errors.UnsupportedError("oversized encrypted session key") 63 } 64 ske.encryptedKey = encryptedKey[:n] 65 } 66 67 return nil 68} 69 70// Decrypt attempts to decrypt an encrypted session key and returns the key and 71// the cipher to use when decrypting a subsequent Symmetrically Encrypted Data 72// packet. 73func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunction, error) { 74 key := make([]byte, ske.CipherFunc.KeySize()) 75 ske.s2k(key, passphrase) 76 77 if len(ske.encryptedKey) == 0 { 78 return key, ske.CipherFunc, nil 79 } 80 81 // the IV is all zeros 82 iv := make([]byte, ske.CipherFunc.blockSize()) 83 c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv) 84 plaintextKey := make([]byte, len(ske.encryptedKey)) 85 c.XORKeyStream(plaintextKey, ske.encryptedKey) 86 cipherFunc := CipherFunction(plaintextKey[0]) 87 if cipherFunc.blockSize() == 0 { 88 return nil, ske.CipherFunc, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) 89 } 90 plaintextKey = plaintextKey[1:] 91 if l, cipherKeySize := len(plaintextKey), cipherFunc.KeySize(); l != cipherFunc.KeySize() { 92 return nil, cipherFunc, errors.StructuralError("length of decrypted key (" + strconv.Itoa(l) + ") " + 93 "not equal to cipher keysize (" + strconv.Itoa(cipherKeySize) + ")") 94 } 95 return plaintextKey, cipherFunc, nil 96} 97 98// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The 99// packet contains a random session key, encrypted by a key derived from the 100// given passphrase. The session key is returned and must be passed to 101// SerializeSymmetricallyEncrypted. 102// If config is nil, sensible defaults will be used. 103func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) { 104 cipherFunc := config.Cipher() 105 keySize := cipherFunc.KeySize() 106 if keySize == 0 { 107 return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) 108 } 109 110 s2kBuf := new(bytes.Buffer) 111 keyEncryptingKey := make([]byte, keySize) 112 // s2k.Serialize salts and stretches the passphrase, and writes the 113 // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf. 114 err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, &s2k.Config{Hash: config.Hash(), S2KCount: config.PasswordHashIterations()}) 115 if err != nil { 116 return 117 } 118 s2kBytes := s2kBuf.Bytes() 119 120 packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize 121 err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength) 122 if err != nil { 123 return 124 } 125 126 var buf [2]byte 127 buf[0] = symmetricKeyEncryptedVersion 128 buf[1] = byte(cipherFunc) 129 _, err = w.Write(buf[:]) 130 if err != nil { 131 return 132 } 133 _, err = w.Write(s2kBytes) 134 if err != nil { 135 return 136 } 137 138 sessionKey := make([]byte, keySize) 139 _, err = io.ReadFull(config.Random(), sessionKey) 140 if err != nil { 141 return 142 } 143 iv := make([]byte, cipherFunc.blockSize()) 144 c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv) 145 encryptedCipherAndKey := make([]byte, keySize+1) 146 c.XORKeyStream(encryptedCipherAndKey, buf[1:]) 147 c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey) 148 _, err = w.Write(encryptedCipherAndKey) 149 if err != nil { 150 return 151 } 152 153 key = sessionKey 154 return 155} 156