summaryrefslogtreecommitdiff
path: root/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go')
-rw-r--r--src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go b/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
new file mode 100644
index 000000000..d9010f88a
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
@@ -0,0 +1,102 @@
+// 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
+}