// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package packet import ( "crypto/cipher" "crypto/openpgp/error" "crypto/openpgp/s2k" "io" "os" "strconv" ) // This is the largest session key that we'll support. Since no 512-bit cipher // has even been seriously used, this is comfortably large. const maxSessionKeySizeInBytes = 64 // SymmetricKeyEncrypted represents a passphrase protected session key. See RFC // 4880, section 5.3. type SymmetricKeyEncrypted struct { CipherFunc CipherFunction Encrypted bool Key []byte // Empty unless Encrypted is false. s2k func(out, in []byte) encryptedKey []byte } func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err os.Error) { // RFC 4880, section 5.3. var buf [2]byte _, err = readFull(r, buf[:]) if err != nil { return } if buf[0] != 4 { return error.UnsupportedError("SymmetricKeyEncrypted version") } ske.CipherFunc = CipherFunction(buf[1]) if ske.CipherFunc.keySize() == 0 { return error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1]))) } ske.s2k, err = s2k.Parse(r) if err != nil { return } encryptedKey := make([]byte, maxSessionKeySizeInBytes) // The session key may follow. We just have to try and read to find // out. If it exists then we limit it to maxSessionKeySizeInBytes. n, err := readFull(r, encryptedKey) if err != nil && err != io.ErrUnexpectedEOF { return } err = nil if n != 0 { if n == maxSessionKeySizeInBytes { return error.UnsupportedError("oversized encrypted session key") } ske.encryptedKey = encryptedKey[:n] } ske.Encrypted = true return } // Decrypt attempts to decrypt an encrypted session key. If it returns nil, // ske.Key will contain the session key. func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) os.Error { if !ske.Encrypted { return nil } key := make([]byte, ske.CipherFunc.keySize()) ske.s2k(key, passphrase) if len(ske.encryptedKey) == 0 { ske.Key = key } else { // the IV is all zeros iv := make([]byte, ske.CipherFunc.blockSize()) c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv) c.XORKeyStream(ske.encryptedKey, ske.encryptedKey) ske.CipherFunc = CipherFunction(ske.encryptedKey[0]) if ske.CipherFunc.blockSize() == 0 { return error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(ske.CipherFunc))) } ske.CipherFunc = CipherFunction(ske.encryptedKey[0]) ske.Key = ske.encryptedKey[1:] if len(ske.Key)%ske.CipherFunc.blockSize() != 0 { ske.Key = nil return error.StructuralError("length of decrypted key not a multiple of block size") } } ske.Encrypted = false return nil }