lists.arthurdejong.org
RSS feed

python-pskc branch master updated. 1.0-8-g924e1f3

[Date Prev][Date Next] [Thread Prev][Thread Next]

python-pskc branch master updated. 1.0-8-g924e1f3



This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-pskc".

The branch, master has been updated
       via  924e1f38e257ac868a1d8a8adc2b6fa7ed45a339 (commit)
       via  be2b49fd90236ee16e5da3564caf3a6b227e46c8 (commit)
       via  e60d7f3356c4808e17e363055fca23fae005f76f (commit)
      from  8054c6e6244de9d5d830a7a24b5ef84d60f8c4b2 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://arthurdejong.org/git/python-pskc/commit/?id=924e1f38e257ac868a1d8a8adc2b6fa7ed45a339

commit 924e1f38e257ac868a1d8a8adc2b6fa7ed45a339
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Thu Feb 8 23:21:33 2018 +0100

    Correctly write a PSKC file without a MAC key
    
    In some cases a PSKC file can be written with a MAC algorithm but
    without a MAC key. This is possible when the MAC key is not supplied
    (allowed in older PSKC versions) and a fallback to the encryption key is
    done. If we have not yet decrypted the file the MAC key is not yet
    available and so can't be included in the written file.

diff --git a/pskc/serialiser.py b/pskc/serialiser.py
index ca6622c..26bf1c2 100644
--- a/pskc/serialiser.py
+++ b/pskc/serialiser.py
@@ -95,6 +95,8 @@ class PSKCSerialiser(object):
             return
         mac_method = mk_elem(
             container, 'pskc:MACMethod', Algorithm=mac.algorithm, empty=True)
+        if not key_value:
+            return
         # encrypt the mac key if needed
         if not hasattr(key_value, 'get_value'):
             key_value = EncryptedValue.create(mac.pskc, key_value)
diff --git a/tests/test_write.doctest b/tests/test_write.doctest
index 34ddb36..4d980d6 100644
--- a/tests/test_write.doctest
+++ b/tests/test_write.doctest
@@ -257,6 +257,98 @@ providing the encryption key.
 </pskc:KeyContainer>
 
 
+Read a legacy encrypted PSKC file and write it out as-is. This should convert
+the format to RFC 6030 format as best it can. Note that this does not include
+a MAC key (but does include a MAC algorithm because the MAC key is not
+specified and we assume to use the encryption key as MAC key).
+
+>>> pskc = 
PSKC('tests/draft-hoyer-keyprov-portable-symmetric-key-container-01/password-encrypted.pskcxml')
+>>> pskc.write(sys.stdout)  #doctest: +ELLIPSIS +REPORT_UDIFF
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer ... Version="1.0">
+ <pskc:EncryptionKey>
+  <xenc11:DerivedKey>
+   <xenc11:KeyDerivationMethod 
Algorithm="http://www.rsasecurity.com/rsalabs/pkcs/schemas/pkcs-5v2-0#pbkdf2";>
+    <xenc11:PBKDF2-params>
+     <Salt>
+      <Specified>y6TzckeLRQw=</Specified>
+     </Salt>
+     <IterationCount>999</IterationCount>
+     <KeyLength>16</KeyLength>
+    </xenc11:PBKDF2-params>
+   </xenc11:KeyDerivationMethod>
+  </xenc11:DerivedKey>
+ </pskc:EncryptionKey>
+ <pskc:MACMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"/>
+ <pskc:KeyPackage>
+  <pskc:DeviceInfo>
+   <pskc:Manufacturer>Token Manufacturer</pskc:Manufacturer>
+   <pskc:SerialNo>98765432187</pskc:SerialNo>
+   <pskc:ExpiryDate>2008-01-01T00:00:00</pskc:ExpiryDate>
+  </pskc:DeviceInfo>
+  <pskc:Key Algorithm="HOTP" Id="77654321870">
+   <pskc:Issuer>Credential Issuer</pskc:Issuer>
+   <pskc:AlgorithmParameters>
+    <pskc:ResponseFormat Encoding="DECIMAL" Length="6"/>
+   </pskc:AlgorithmParameters>
+   <pskc:FriendlyName>MySecondToken</pskc:FriendlyName>
+   <pskc:Data>
+    <pskc:Secret>
+     <pskc:EncryptedValue>
+      <xenc:EncryptionMethod 
Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
+      <xenc:CipherData>
+       <xenc:CipherValue>F/CY93NYc/SvmxT3oB6PzG7p6zpG92/t</xenc:CipherValue>
+      </xenc:CipherData>
+     </pskc:EncryptedValue>
+     <pskc:ValueMAC>hN793ZE7GM6yCM6gz9OKNRzibhg=</pskc:ValueMAC>
+    </pskc:Secret>
+    <pskc:Counter>
+     <pskc:EncryptedValue>
+      <xenc:EncryptionMethod 
Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
+      <xenc:CipherData>
+       <xenc:CipherValue>VVBYqRF1QSpetvIB2vBAzw==</xenc:CipherValue>
+      </xenc:CipherData>
+     </pskc:EncryptedValue>
+     <pskc:ValueMAC>6clqJvT9l0xIZtWSch2t6zr0IwU=</pskc:ValueMAC>
+    </pskc:Counter>
+   </pskc:Data>
+  </pskc:Key>
+ </pskc:KeyPackage>
+</pskc:KeyContainer>
+
+If we decrypt the file the MAC key will be included in encrypted form.
+
+>>> pskc.encryption.derive_key('qwerty')
+>>> pskc.write(sys.stdout)  #doctest: +ELLIPSIS +REPORT_UDIFF
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer ... Version="1.0">
+ <pskc:EncryptionKey>
+  <xenc11:DerivedKey>
+   <xenc11:KeyDerivationMethod 
Algorithm="http://www.rsasecurity.com/rsalabs/pkcs/schemas/pkcs-5v2-0#pbkdf2";>
+    <xenc11:PBKDF2-params>
+     <Salt>
+      <Specified>y6TzckeLRQw=</Specified>
+     </Salt>
+     <IterationCount>999</IterationCount>
+     <KeyLength>16</KeyLength>
+    </xenc11:PBKDF2-params>
+   </xenc11:KeyDerivationMethod>
+  </xenc11:DerivedKey>
+ </pskc:EncryptionKey>
+ <pskc:MACMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1";>
+  <pskc:MACKey>
+   <xenc:EncryptionMethod 
Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
+   <xenc:CipherData>
+    <xenc:CipherValue>...</xenc:CipherValue>
+   </xenc:CipherData>
+  </pskc:MACKey>
+ </pskc:MACMethod>
+ <pskc:KeyPackage>
+...
+ </pskc:KeyPackage>
+</pskc:KeyContainer>
+
+
 Set up an encrypted PSKC file and generate a pre-shared key for it.
 
 >>> pskc = PSKC()

https://arthurdejong.org/git/python-pskc/commit/?id=be2b49fd90236ee16e5da3564caf3a6b227e46c8

commit be2b49fd90236ee16e5da3564caf3a6b227e46c8
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sun Feb 4 16:08:47 2018 +0100

    Correctly write a PSKC file with a global IV
    
    This ensures that the encryption IV, which should be per encrypted value
    is written out per encrypted value instead of globally. This is mostly
    useful for when reading an old format PSKC file and writing out a RFC
    6030 compliant one.

diff --git a/pskc/encryption.py b/pskc/encryption.py
index 35b7c79..e1f56c9 100644
--- a/pskc/encryption.py
+++ b/pskc/encryption.py
@@ -402,7 +402,10 @@ class Encryption(object):
 
     def encrypt_value(self, plaintext):
         """Encrypt the provided value and return the cipher_value."""
-        return encrypt(self.algorithm, self.key, plaintext, self.iv)
+        cipher_value = encrypt(self.algorithm, self.key, plaintext, self.iv)
+        if self.iv:
+            cipher_value = cipher_value[len(self.iv):]
+        return cipher_value
 
     def remove_encryption(self):
         """Decrypt all values and remove the encryption from the PSKC file."""
diff --git a/pskc/serialiser.py b/pskc/serialiser.py
index 8020f60..ca6622c 100644
--- a/pskc/serialiser.py
+++ b/pskc/serialiser.py
@@ -100,11 +100,14 @@ class PSKCSerialiser(object):
             key_value = EncryptedValue.create(mac.pskc, key_value)
         # construct encrypted MACKey
         algorithm = key_value.algorithm or mac.pskc.encryption.algorithm
+        cipher_value = key_value.cipher_value
+        if mac.pskc.encryption.iv:
+            cipher_value = mac.pskc.encryption.iv + cipher_value
         mac_key = mk_elem(mac_method, 'pskc:MACKey', empty=True)
         mk_elem(mac_key, 'xenc:EncryptionMethod', Algorithm=algorithm)
         cipher_data = mk_elem(mac_key, 'xenc:CipherData', empty=True)
         mk_elem(cipher_data, 'xenc:CipherValue',
-                base64.b64encode(key_value.cipher_value).decode())
+                base64.b64encode(cipher_value).decode())
 
     @classmethod
     def serialise_key_package(cls, device, container):
@@ -195,6 +198,9 @@ class PSKCSerialiser(object):
         else:
             # encrypted value
             algorithm = value.algorithm or pskc.encryption.algorithm
+            cipher_value = value.cipher_value
+            if pskc.encryption.iv:
+                cipher_value = pskc.encryption.iv + cipher_value
             encrypted_value = mk_elem(
                 element, 'pskc:EncryptedValue', empty=True)
             mk_elem(encrypted_value, 'xenc:EncryptionMethod',
@@ -202,7 +208,7 @@ class PSKCSerialiser(object):
             cipher_data = mk_elem(
                 encrypted_value, 'xenc:CipherData', empty=True)
             mk_elem(cipher_data, 'xenc:CipherValue',
-                    base64.b64encode(value.cipher_value).decode())
+                    base64.b64encode(cipher_value).decode())
             if value.mac_value:
                 mk_elem(element, 'pskc:ValueMAC',
                         base64.b64encode(value.mac_value).decode())
diff --git a/tests/test_write.doctest b/tests/test_write.doctest
index 1ea806a..34ddb36 100644
--- a/tests/test_write.doctest
+++ b/tests/test_write.doctest
@@ -1,6 +1,6 @@
 test_write.doctest - tests for writing PSKC files
 
-Copyright (C) 2014-2017 Arthur de Jong
+Copyright (C) 2014-2018 Arthur de Jong
 
 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
@@ -563,3 +563,41 @@ set on one key end up being applied to both keys.
   </pskc:Key>
  </pskc:KeyPackage>
 </pskc:KeyContainer>
+
+
+If we specify a global IV it will be used for all encrypted values but will
+be not be written as a global IV in the PSKC file because RFC 6030 does not
+specify this (and re-using an IV is a bad idea).
+
+>>> pskc = PSKC()
+>>> key = pskc.add_key(secret='1234')
+>>> 
pskc.encryption.setup_preshared_key(key=a2b_hex('12345678901234567890123456789012'))
+>>> pskc.encryption.iv = a2b_hex('000102030405060708090a0b0c0d0e0f')
+>>> pskc.write(sys.stdout)  #doctest: +ELLIPSIS +REPORT_UDIFF
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer ... Version="1.0">
+ <pskc:EncryptionKey/>
+ <pskc:MACMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1";>
+  <pskc:MACKey>
+   <xenc:EncryptionMethod 
Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
+   <xenc:CipherData>
+    <xenc:CipherValue>AAECAwQFBgcICQoLDA0OD...</xenc:CipherValue>
+   </xenc:CipherData>
+  </pskc:MACKey>
+ </pskc:MACMethod>
+ <pskc:KeyPackage>
+  <pskc:Key>
+   <pskc:Data>
+    <pskc:Secret>
+     <pskc:EncryptedValue>
+      <xenc:EncryptionMethod 
Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
+      <xenc:CipherData>
+       <xenc:CipherValue>AAECAwQFBgcICQoLDA0OD...</xenc:CipherValue>
+      </xenc:CipherData>
+     </pskc:EncryptedValue>
+     <pskc:ValueMAC>...</pskc:ValueMAC>
+    </pskc:Secret>
+   </pskc:Data>
+  </pskc:Key>
+ </pskc:KeyPackage>
+</pskc:KeyContainer>

https://arthurdejong.org/git/python-pskc/commit/?id=e60d7f3356c4808e17e363055fca23fae005f76f

commit e60d7f3356c4808e17e363055fca23fae005f76f
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Wed Feb 7 20:04:31 2018 +0100

    Also use EncryptedValue for MAC key
    
    This ensures that an encrypted MAC key is hanled in the same way as
    normal encrypted data values.
    
    This also ensures consistent fallback to the globally configured
    encryption algorithm if no value has been set in the EncryptedValue.

diff --git a/pskc/mac.py b/pskc/mac.py
index 65ec9b3..38552dd 100644
--- a/pskc/mac.py
+++ b/pskc/mac.py
@@ -1,7 +1,7 @@
 # mac.py - module for checking value signatures
 # coding: utf-8
 #
-# Copyright (C) 2014-2017 Arthur de Jong
+# Copyright (C) 2014-2018 Arthur de Jong
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -81,25 +81,22 @@ class MAC(object):
     def __init__(self, pskc):
         self.pskc = pskc
         self._algorithm = None
-        self.key_plain_value = None
-        self.key_cipher_value = None
-        self.key_algorithm = None
 
     @property
     def key(self):
         """Provide access to the MAC key binary value if available."""
-        if self.key_plain_value:
-            return self.key_plain_value
-        elif self.key_cipher_value:
-            return self.pskc.encryption.decrypt_value(
-                self.key_cipher_value, self.key_algorithm)
-        # fall back to encryption key
-        return self.pskc.encryption.key
+        value = getattr(self, '_key', None)
+        if hasattr(value, 'get_value'):
+            return value.get_value(self.pskc)
+        elif value:
+            return value
+        else:
+            # fall back to encryption key
+            return self.pskc.encryption.key
 
     @key.setter
     def key(self, value):
-        self.key_plain_value = value
-        self.key_cipher_value = None
+        self._key = value
 
     @property
     def algorithm(self):
diff --git a/pskc/parser.py b/pskc/parser.py
index 11486f8..b3e7952 100644
--- a/pskc/parser.py
+++ b/pskc/parser.py
@@ -157,8 +157,8 @@ class PSKCParser(object):
             mac_method.get('algorithm'))
         mac_key = find(mac_method, 'MACKey')
         if mac_key is not None:
-            mac.key_algorithm, mac.key_cipher_value = (
-                cls.parse_encrypted_value(mac_key))
+            algorithm, cipher_value = cls.parse_encrypted_value(mac_key)
+            mac.key = EncryptedValue(cipher_value, None, algorithm)
 
     @classmethod
     def parse_key_package(cls, device, key_package):
diff --git a/pskc/serialiser.py b/pskc/serialiser.py
index c71f6ea..8020f60 100644
--- a/pskc/serialiser.py
+++ b/pskc/serialiser.py
@@ -90,22 +90,21 @@ class PSKCSerialiser(object):
 
     @classmethod
     def serialise_mac(cls, mac, container):
-        if not mac.algorithm and not mac.key:
+        key_value = getattr(mac, '_key', None) or mac.pskc.encryption.key
+        if not mac.algorithm and not key_value:
             return
         mac_method = mk_elem(
             container, 'pskc:MACMethod', Algorithm=mac.algorithm, empty=True)
+        # encrypt the mac key if needed
+        if not hasattr(key_value, 'get_value'):
+            key_value = EncryptedValue.create(mac.pskc, key_value)
+        # construct encrypted MACKey
+        algorithm = key_value.algorithm or mac.pskc.encryption.algorithm
         mac_key = mk_elem(mac_method, 'pskc:MACKey', empty=True)
-        mk_elem(
-            mac_key, 'xenc:EncryptionMethod',
-            Algorithm=mac.pskc.encryption.algorithm)
+        mk_elem(mac_key, 'xenc:EncryptionMethod', Algorithm=algorithm)
         cipher_data = mk_elem(mac_key, 'xenc:CipherData', empty=True)
-        if mac.key_cipher_value:
-            mk_elem(cipher_data, 'xenc:CipherValue',
-                    base64.b64encode(mac.key_cipher_value).decode())
-        elif mac.key_plain_value:
-            mk_elem(cipher_data, 'xenc:CipherValue',
-                    base64.b64encode(mac.pskc.encryption.encrypt_value(
-                        mac.key_plain_value)).decode())
+        mk_elem(cipher_data, 'xenc:CipherValue',
+                base64.b64encode(key_value.cipher_value).decode())
 
     @classmethod
     def serialise_key_package(cls, device, container):
@@ -195,10 +194,11 @@ class PSKCSerialiser(object):
             mk_elem(element, 'pskc:PlainValue', value2text(value))
         else:
             # encrypted value
+            algorithm = value.algorithm or pskc.encryption.algorithm
             encrypted_value = mk_elem(
                 element, 'pskc:EncryptedValue', empty=True)
             mk_elem(encrypted_value, 'xenc:EncryptionMethod',
-                    Algorithm=value.algorithm)
+                    Algorithm=algorithm)
             cipher_data = mk_elem(
                 encrypted_value, 'xenc:CipherData', empty=True)
             mk_elem(cipher_data, 'xenc:CipherValue',

-----------------------------------------------------------------------

Summary of changes:
 pskc/encryption.py       |   5 +-
 pskc/mac.py              |  23 ++++-----
 pskc/parser.py           |   4 +-
 pskc/serialiser.py       |  34 +++++++-----
 tests/test_write.doctest | 132 ++++++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 168 insertions(+), 30 deletions(-)


hooks/post-receive
-- 
python-pskc
-- 
To unsubscribe send an email to
python-pskc-commits-unsubscribe@lists.arthurdejong.org or see
https://lists.arthurdejong.org/python-pskc-commits/