| // 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 |
| } |