summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLegrandin <gooksankoo@hoiptorrow.mailexpire.com>2012-05-17 13:28:24 +0200
committerLegrandin <gooksankoo@hoiptorrow.mailexpire.com>2012-05-17 22:17:38 +0200
commit62f2c4154c89fecbacb722efaed2af01bcecab3a (patch)
tree6640a6228b5784aa32ce390b342fdcfe933a23d4
parent1eec0099f32e2ea3c9e350eab5b4fcb09e28038d (diff)
downloadpycrypto-62f2c4154c89fecbacb722efaed2af01bcecab3a.tar.gz
Added OpenPGP mode
-rw-r--r--lib/Crypto/Cipher/AES.py14
-rw-r--r--lib/Crypto/Cipher/ARC2.py14
-rw-r--r--lib/Crypto/Cipher/Blowfish.py14
-rw-r--r--lib/Crypto/Cipher/CAST.py14
-rw-r--r--lib/Crypto/Cipher/DES.py14
-rw-r--r--lib/Crypto/Cipher/DES3.py14
-rw-r--r--lib/Crypto/Cipher/blockalgo.py126
-rw-r--r--lib/Crypto/SelfTest/Cipher/common.py27
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_AES.py29
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_DES3.py12
10 files changed, 254 insertions, 24 deletions
diff --git a/lib/Crypto/Cipher/AES.py b/lib/Crypto/Cipher/AES.py
index 6b870ac..14f68d8 100644
--- a/lib/Crypto/Cipher/AES.py
+++ b/lib/Crypto/Cipher/AES.py
@@ -71,8 +71,16 @@ def new(key, *args, **kwargs):
Default is `MODE_ECB`.
IV : byte string
The initialization vector to use for encryption or decryption.
- It must be `block_size` bytes longs. Ignored for `MODE_ECB`
- and `MODE_CTR`. The default value is all zeroes.
+
+ It is ignored for `MODE_ECB` and `MODE_CTR`.
+
+ For `MODE_OPENPGP`, IV must be `block_size` bytes long for encryption
+ and `block_size` +2 bytes for decryption (in the latter case, it is
+ actually the *encrypted* IV which was prefixed to the ciphertext).
+ It is mandatory.
+
+ For all other modes, it must be `block_size` bytes longs. It is optional and
+ when not present it will be given a default value of all zeroes.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
@@ -98,6 +106,8 @@ MODE_PGP = 4
MODE_OFB = 5
#: CounTer Mode (CTR). See `blockalgo.MODE_CTR`.
MODE_CTR = 6
+#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
+MODE_OPENPGP = 7
#: Size of a data block (in bytes)
block_size = 16
#: Size of a key (in bytes)
diff --git a/lib/Crypto/Cipher/ARC2.py b/lib/Crypto/Cipher/ARC2.py
index e9284a1..7b5f43a 100644
--- a/lib/Crypto/Cipher/ARC2.py
+++ b/lib/Crypto/Cipher/ARC2.py
@@ -83,8 +83,16 @@ def new(key, *args, **kwargs):
Default is `MODE_ECB`.
IV : byte string
The initialization vector to use for encryption or decryption.
- It must be `block_size` bytes longs. Ignored for `MODE_ECB`
- and `MODE_CTR`. The default value is all zeroes.
+
+ It is ignored for `MODE_ECB` and `MODE_CTR`.
+
+ For `MODE_OPENPGP`, IV must be `block_size` bytes long for encryption
+ and `block_size` +2 bytes for decryption (in the latter case, it is
+ actually the *encrypted* IV which was prefixed to the ciphertext).
+ It is mandatory.
+
+ For all other modes, it must be `block_size` bytes longs. It is optional and
+ when not present it will be given a default value of all zeroes.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
@@ -113,6 +121,8 @@ MODE_PGP = 4
MODE_OFB = 5
#: CounTer Mode (CTR). See `blockalgo.MODE_CTR`.
MODE_CTR = 6
+#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
+MODE_OPENPGP = 7
#: Size of a data block (in bytes)
block_size = 8
#: Size of a key (in bytes)
diff --git a/lib/Crypto/Cipher/Blowfish.py b/lib/Crypto/Cipher/Blowfish.py
index f060689..3f12bea 100644
--- a/lib/Crypto/Cipher/Blowfish.py
+++ b/lib/Crypto/Cipher/Blowfish.py
@@ -77,8 +77,16 @@ def new(key, *args, **kwargs):
Default is `MODE_ECB`.
IV : byte string
The initialization vector to use for encryption or decryption.
- It must be `block_size` bytes longs. Ignored for `MODE_ECB`
- and `MODE_CTR`. The default value is all zeroes.
+
+ It is ignored for `MODE_ECB` and `MODE_CTR`.
+
+ For `MODE_OPENPGP`, IV must be `block_size` bytes long for encryption
+ and `block_size` +2 bytes for decryption (in the latter case, it is
+ actually the *encrypted* IV which was prefixed to the ciphertext).
+ It is mandatory.
+
+ For all other modes, it must be `block_size` bytes longs. It is optional and
+ when not present it will be given a default value of all zeroes.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
@@ -104,6 +112,8 @@ MODE_PGP = 4
MODE_OFB = 5
#: CounTer Mode (CTR). See `blockalgo.MODE_CTR`.
MODE_CTR = 6
+#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
+MODE_OPENPGP = 7
#: Size of a data block (in bytes)
block_size = 8
#: Size of a key (in bytes)
diff --git a/lib/Crypto/Cipher/CAST.py b/lib/Crypto/Cipher/CAST.py
index f47e65b..1734b53 100644
--- a/lib/Crypto/Cipher/CAST.py
+++ b/lib/Crypto/Cipher/CAST.py
@@ -74,8 +74,16 @@ def new(key, *args, **kwargs):
Default is `MODE_ECB`.
IV : byte string
The initialization vector to use for encryption or decryption.
- It must be `block_size` bytes longs. Ignored for `MODE_ECB`
- and `MODE_CTR`. The default value is all zeroes.
+
+ It is ignored for `MODE_ECB` and `MODE_CTR`.
+
+ For `MODE_OPENPGP`, IV must be `block_size` bytes long for encryption
+ and `block_size` +2 bytes for decryption (in the latter case, it is
+ actually the *encrypted* IV which was prefixed to the ciphertext).
+ It is mandatory.
+
+ For all other modes, it must be `block_size` bytes longs. It is optional and
+ when not present it will be given a default value of all zeroes.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
@@ -101,6 +109,8 @@ MODE_PGP = 4
MODE_OFB = 5
#: CounTer Mode (CTR). See `blockalgo.MODE_CTR`.
MODE_CTR = 6
+#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
+MODE_OPENPGP = 7
#: Size of a data block (in bytes)
block_size = 8
#: Size of a key (in bytes)
diff --git a/lib/Crypto/Cipher/DES.py b/lib/Crypto/Cipher/DES.py
index d4300c6..2fae42f 100644
--- a/lib/Crypto/Cipher/DES.py
+++ b/lib/Crypto/Cipher/DES.py
@@ -75,8 +75,16 @@ def new(key, *args, **kwargs):
Default is `MODE_ECB`.
IV : byte string
The initialization vector to use for encryption or decryption.
- It must be `block_size` bytes longs. Ignored for `MODE_ECB`
- and `MODE_CTR`. The default value is all zeroes.
+
+ It is ignored for `MODE_ECB` and `MODE_CTR`.
+
+ For `MODE_OPENPGP`, IV must be `block_size` bytes long for encryption
+ and `block_size` +2 bytes for decryption (in the latter case, it is
+ actually the *encrypted* IV which was prefixed to the ciphertext).
+ It is mandatory.
+
+ For all other modes, it must be `block_size` bytes longs. It is optional and
+ when not present it will be given a default value of all zeroes.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
@@ -102,6 +110,8 @@ MODE_PGP = 4
MODE_OFB = 5
#: CounTer Mode (CTR). See `blockalgo.MODE_CTR`.
MODE_CTR = 6
+#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
+MODE_OPENPGP = 7
#: Size of a data block (in bytes)
block_size = 8
#: Size of a key (in bytes)
diff --git a/lib/Crypto/Cipher/DES3.py b/lib/Crypto/Cipher/DES3.py
index 39e726c..7fedac8 100644
--- a/lib/Crypto/Cipher/DES3.py
+++ b/lib/Crypto/Cipher/DES3.py
@@ -88,8 +88,16 @@ def new(key, *args, **kwargs):
Default is `MODE_ECB`.
IV : byte string
The initialization vector to use for encryption or decryption.
- It must be `block_size` bytes longs. Ignored for `MODE_ECB`
- and `MODE_CTR`. The default value is all zeroes.
+
+ It is ignored for `MODE_ECB` and `MODE_CTR`.
+
+ For `MODE_OPENPGP`, IV must be `block_size` bytes long for encryption
+ and `block_size` +2 bytes for decryption (in the latter case, it is
+ actually the *encrypted* IV which was prefixed to the ciphertext).
+ It is mandatory.
+
+ For all other modes, it must be `block_size` bytes longs. It is optional and
+ when not present it will be given a default value of all zeroes.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
@@ -117,6 +125,8 @@ MODE_PGP = 4
MODE_OFB = 5
#: CounTer Mode (CTR). See `blockalgo.MODE_CTR`.
MODE_CTR = 6
+#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
+MODE_OPENPGP = 7
#: Size of a data block (in bytes)
block_size = 8
#: Size of a key (in bytes)
diff --git a/lib/Crypto/Cipher/blockalgo.py b/lib/Crypto/Cipher/blockalgo.py
index d8b1a8c..8863a7d 100644
--- a/lib/Crypto/Cipher/blockalgo.py
+++ b/lib/Crypto/Cipher/blockalgo.py
@@ -21,6 +21,9 @@
# ===================================================================
"""Module with definitions common to all block ciphers."""
+from Crypto.Util.py21compat import *
+from Crypto.Util.py3compat import *
+
#: *Electronic Code Book (ECB)*.
#: This is the simplest encryption mode. Each of the plaintext blocks
#: is directly encrypted into a ciphertext block, independently of
@@ -105,14 +108,79 @@ MODE_OFB = 5
#: .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
MODE_CTR = 6
+#: OpenPGP. This mode is a variant of CFB, and it is only used in PGP and OpenPGP_ applications.
+#: A Initialization Vector (*IV*) is required.
+#:
+#: Unlike CFB, the IV is not transmitted to the receiver. Instead, the *encrypted* IV is.
+#: The IV is a random data block. Two of its bytes are duplicated to act as a checksum
+#: for the correctness of the key. The encrypted IV is therefore 2 bytes longer than
+#: the clean IV.
+#:
+#: .. _OpenPGP: http://tools.ietf.org/html/rfc4880
+MODE_OPENPGP = 7
+
+def _getParameter(name, index, args, kwargs, default=None):
+ """Find a parameter in tuple and dictionary arguments a function receives"""
+ param = kwargs.get(name)
+ if len(args)>index:
+ if param:
+ raise ValueError("Parameter '%s' is specified twice" % name)
+ param = args[index]
+ return param or default
+
class BlockAlgo:
"""Class modelling an abstract block cipher."""
def __init__(self, factory, key, *args, **kwargs):
- self._cipher = factory.new(key, *args, **kwargs)
- self.block_size = self._cipher.block_size
- self.mode = self._cipher.mode
- self.IV = self._cipher.IV
+ self.mode = _getParameter('mode', 0, args, kwargs, default=MODE_ECB)
+ self.block_size = factory.block_size
+
+ if self.mode != MODE_OPENPGP:
+ self._cipher = factory.new(key, *args, **kwargs)
+ self.IV = self._cipher.IV
+ else:
+ # OPENPGP mode. For details, see 13.9 in RCC4880.
+ #
+ # A few members are specifically created for this mode:
+ # - _encrypted_iv, set in this constructor
+ # - _done_first_block, set to True after the first encryption
+ # - _done_last_block, set to True after a partial block is processed
+
+ self._done_first_block = False
+ self._done_last_block = False
+ self.IV = _getParameter('iv', 1, args, kwargs)
+ if not self.IV:
+ raise ValueError("MODE_OPENPGP requires an IV")
+
+ # Instantiate a temporary cipher to process the IV
+ IV_cipher = factory.new(key, MODE_CFB,
+ b('\x00')*self.block_size, # IV for CFB
+ segment_size=self.block_size*8)
+
+ # The cipher will be used for...
+ if len(self.IV) == self.block_size:
+ # ... encryption
+ self._encrypted_IV = IV_cipher.encrypt(
+ self.IV + self.IV[-2:] + # Plaintext
+ b('\x00')*(self.block_size-2) # Padding
+ )[:self.block_size+2]
+ elif len(self.IV) == self.block_size+2:
+ # ... decryption
+ self._encrypted_IV = self.IV
+ self.IV = IV_cipher.decrypt(self.IV + # Ciphertext
+ b('\x00')*(self.block_size-2) # Padding
+ )[:self.block_size+2]
+ if self.IV[-2:] != self.IV[-4:-2]:
+ raise ValueError("Failed integrity check for OPENPGP IV")
+ self.IV = self.IV[:-2]
+ else:
+ raise ValueError("Length of IV must be %d or %d bytes for MODE_OPENPGP"
+ % (self.block_size, self.block_size+2))
+
+ # Instantiate the cipher for the real PGP data
+ self._cipher = factory.new(key, MODE_CFB,
+ self._encrypted_IV[-self.block_size:],
+ segment_size=self.block_size*8)
def encrypt(self, plaintext):
"""Encrypt data with the key and the parameters set at initialization.
@@ -140,12 +208,37 @@ class BlockAlgo:
- For `MODE_CTR`, *plaintext* can be of any length.
+ - For `MODE_OPENPGP`, *plaintext* must be a multiple of *block_size*,
+ unless it is the last chunk of the message.
+
:Parameters:
plaintext : byte string
The piece of data to encrypt.
- :Return: the encrypted data (as a byte string, as long as the
- plaintext)
+ :Return:
+ the encrypted data, as a byte string. It is as long as
+ *plaintext* with one exception: when encrypting the first message
+ chunk with `MODE_OPENPGP`, the encypted IV is prepended to the
+ returned ciphertext.
"""
+
+ if self.mode == MODE_OPENPGP:
+ padding_length = (self.block_size - len(plaintext) % self.block_size) % self.block_size
+ if padding_length>0:
+ # CFB mode requires ciphertext to have length multiple of block size,
+ # but PGP mode allows the last block to be shorter
+ if self._done_last_block:
+ raise ValueError("Only the last chunk is allowed to have length not multiple of %d bytes",
+ self.block_size)
+ self._done_last_block = True
+ padded = plaintext + b('\x00')*padding_length
+ res = self._cipher.encrypt(padded)[:len(plaintext)]
+ else:
+ res = self._cipher.encrypt(plaintext)
+ if not self._done_first_block:
+ res = self._encrypted_IV + res
+ self._done_first_block = True
+ return res
+
return self._cipher.encrypt(plaintext)
def decrypt(self, ciphertext):
@@ -174,11 +267,28 @@ class BlockAlgo:
- For `MODE_CTR`, *ciphertext* can be of any length.
+ - For `MODE_OPENPGP`, *plaintext* must be a multiple of *block_size*,
+ unless it is the last chunk of the message.
+
:Parameters:
ciphertext : byte string
The piece of data to decrypt.
- :Return: the decrypted data (as a byte string, as long as the
- ciphertext)
+ :Return: the decrypted data (byte string, as long as *ciphertext*).
"""
+ if self.mode == MODE_OPENPGP:
+ padding_length = (self.block_size - len(ciphertext) % self.block_size) % self.block_size
+ if padding_length>0:
+ # CFB mode requires ciphertext to have length multiple of block size,
+ # but PGP mode allows the last block to be shorter
+ if self._done_last_block:
+ raise ValueError("Only the last chunk is allowed to have length not multiple of %d bytes",
+ self.block_size)
+ self._done_last_block = True
+ padded = ciphertext + b('\x00')*padding_length
+ res = self._cipher.decrypt(padded)[:len(ciphertext)]
+ else:
+ res = self._cipher.decrypt(ciphertext)
+ return res
+
return self._cipher.decrypt(ciphertext)
diff --git a/lib/Crypto/SelfTest/Cipher/common.py b/lib/Crypto/SelfTest/Cipher/common.py
index c48cb7f..9afa147 100644
--- a/lib/Crypto/SelfTest/Cipher/common.py
+++ b/lib/Crypto/SelfTest/Cipher/common.py
@@ -74,6 +74,11 @@ class CipherSelfTest(unittest.TestCase):
self.mode = getattr(self.module, "MODE_" + mode)
self.iv = _extract(params, 'iv', None)
if self.iv is not None: self.iv = b(self.iv)
+
+ # Only relevant for OPENPGP mode
+ self.encrypted_iv = _extract(params, 'encrypted_iv', None)
+ if self.encrypted_iv is not None:
+ self.encrypted_iv = b(self.encrypted_iv)
else:
# Stream cipher
self.mode = None
@@ -84,7 +89,7 @@ class CipherSelfTest(unittest.TestCase):
def shortDescription(self):
return self.description
- def _new(self):
+ def _new(self, do_decryption=0):
params = self.extra_params.copy()
# Handle CTR mode parameters. By default, we use Counter.new(self.module.block_size)
@@ -106,16 +111,30 @@ class CipherSelfTest(unittest.TestCase):
return self.module.new(a2b_hex(self.key), self.mode, **params)
else:
# Block cipher with iv
- return self.module.new(a2b_hex(self.key), self.mode, a2b_hex(self.iv), **params)
+ if do_decryption and self.mode == self.module.MODE_OPENPGP:
+ # In PGP mode, the IV to feed for decryption is the *encrypted* one
+ return self.module.new(a2b_hex(self.key), self.mode, a2b_hex(self.encrypted_iv), **params)
+ else:
+ return self.module.new(a2b_hex(self.key), self.mode, a2b_hex(self.iv), **params)
def runTest(self):
plaintext = a2b_hex(self.plaintext)
ciphertext = a2b_hex(self.ciphertext)
ct1 = b2a_hex(self._new().encrypt(plaintext))
- pt1 = b2a_hex(self._new().decrypt(ciphertext))
+ pt1 = b2a_hex(self._new(1).decrypt(ciphertext))
ct2 = b2a_hex(self._new().encrypt(plaintext))
- pt2 = b2a_hex(self._new().decrypt(ciphertext))
+ pt2 = b2a_hex(self._new(1).decrypt(ciphertext))
+
+ if hasattr(self.module, "MODE_OPENPGP") and self.mode == self.module.MODE_OPENPGP:
+ # In PGP mode, data returned by the first encrypt()
+ # is prefixed with the encrypted IV.
+ # Here we check it and then remove it from the ciphertexts.
+ eilen = len(self.encrypted_iv)
+ self.assertEqual(self.encrypted_iv, ct1[:eilen])
+ self.assertEqual(self.encrypted_iv, ct2[:eilen])
+ ct1 = ct1[eilen:]
+ ct2 = ct2[eilen:]
self.assertEqual(self.ciphertext, ct1) # encrypt
self.assertEqual(self.ciphertext, ct2) # encrypt (second time)
diff --git a/lib/Crypto/SelfTest/Cipher/test_AES.py b/lib/Crypto/SelfTest/Cipher/test_AES.py
index cc54afb..ce87fe3 100644
--- a/lib/Crypto/SelfTest/Cipher/test_AES.py
+++ b/lib/Crypto/SelfTest/Cipher/test_AES.py
@@ -28,6 +28,7 @@ __revision__ = "$Id$"
from common import dict # For compatibility with Python 2.1 and 2.2
from Crypto.Util.py3compat import *
+from binascii import hexlify
# This is a list of (plaintext, ciphertext, key[, description[, params]]) tuples.
test_data = [
@@ -1253,6 +1254,34 @@ test_data = [
'ff7a617ce69148e4f1726e2f43581de2'+'aa62d9f805532edff1eed687fb54153d',
'RFC 3686 Test Vector #9: Encrypting 36 octets using AES-CTR with 256-bit key',
dict(mode='CTR', ctr_params=dict(nbits=32, prefix='001cc5b7'+'51a51d70a1c11148'))),
+
+ # The following test vectors have been generated with gpg v1.4.0.
+ # The command line used was:
+ #
+ # gpg -c -z 0 --cipher-algo AES --passphrase secret_passphrase \
+ # --disable-mdc --s2k-mode 0 --output ct pt
+ #
+ # As result, the content of the file 'pt' is encrypted with a key derived
+ # from 'secret_passphrase' and written to file 'ct'.
+ # Test vectors must be extracted from 'ct', which is a collection of
+ # TLVs (see RFC4880 for all details):
+ # - the encrypted data (with the encrypted IV as prefix) is the payload
+ # of the TLV with tag 9 (Symmetrical Encrypted Data Packet).
+ # This is the ciphertext in the test vector.
+ # - inside the encrypted part, there is a further layer of TLVs. One must
+ # look for tag 11 (Literal Data Packet); in its payload, after a short
+ # but time dependent header, there is the content of file 'pt'.
+ # In the test vector, the plaintext is the complete set of TLVs that gets
+ # encrypted. It is not just the content of 'pt'.
+ # - the key is the leftmost 16 bytes of the SHA1 digest of the password.
+ # The test vector contains such shortened digest.
+ #
+ # Note that encryption uses a clear IV, and decryption an encrypted IV
+ ( 'ac18620270744fb4f647426c61636b4361745768697465436174', # Plaintext, 'BlackCatWhiteCat'
+ 'dc6b9e1f095de609765c59983db5956ae4f63aea7405389d2ebb', # Ciphertext
+ '5baa61e4c9b93f3f0682250b6cf8331b', # Key (hash of 'password')
+ 'GPG Test Vector #1',
+ dict(mode='OPENPGP', iv='3d7d3e62282add7eb203eeba5c800733', encrypted_iv='fd934601ef49cb58b6d9aebca6056bdb96ef' ) ),
]
def get_tests(config={}):
diff --git a/lib/Crypto/SelfTest/Cipher/test_DES3.py b/lib/Crypto/SelfTest/Cipher/test_DES3.py
index 6a8626e..50e969b 100644
--- a/lib/Crypto/SelfTest/Cipher/test_DES3.py
+++ b/lib/Crypto/SelfTest/Cipher/test_DES3.py
@@ -28,6 +28,7 @@ __revision__ = "$Id$"
from common import dict # For compatibility with Python 2.1 and 2.2
from Crypto.Util.py3compat import *
+from binascii import hexlify
# This is a list of (plaintext, ciphertext, key, description) tuples.
SP800_20_A1_KEY = '01' * 24
@@ -306,6 +307,17 @@ test_data = [
# output.
('21e81b7ade88a259', '5c577d4d9b20c0f8',
'9b397ebf81b1181e282f4bb8adbadc6b', 'Two-key 3DES'),
+
+ # The following test vectors have been generated with gpg v1.4.0.
+ # The command line used was:
+ # gpg -c -z 0 --cipher-algo 3DES --passphrase secret_passphrase \
+ # --disable-mdc --s2k-mode 0 --output ct pt
+ # For an explanation, see test_AES.py .
+ ( 'ac1762037074324fb53ba3596f73656d69746556616c6c6579', # Plaintext, 'YosemiteValley'
+ '9979238528357b90e2e0be549cb0b2d5999b9a4a447e5c5c7d', # Ciphertext
+ '7ade65b460f5ea9be35f9e14aa883a2048e3824aa616c0b2', # Key (hash of 'BearsAhead')
+ 'GPG Test Vector #1',
+ dict(mode='OPENPGP', iv='cd47e2afb8b7e4b0', encrypted_iv='6a7eef0b58050e8b904a' ) ),
]
def get_tests(config={}):