lists.arthurdejong.org
RSS feed

python-pskc branch master updated. 1.0-9-g03ee35d

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

python-pskc branch master updated. 1.0-9-g03ee35d



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  03ee35d2ce72cb4d84c6f01bd699321aff92d4cf (commit)
      from  924e1f38e257ac868a1d8a8adc2b6fa7ed45a339 (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=03ee35d2ce72cb4d84c6f01bd699321aff92d4cf

commit 03ee35d2ce72cb4d84c6f01bd699321aff92d4cf
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sat Feb 10 11:22:10 2018 +0100

    Add a pskc2pskc script for converting PSKC files
    
    This script reads a PSKC file in any supported format and writes out a
    RFC 6030 compliant version of the file, optionally with the encryption
    removed or (re-)encrypting the file with a new key.

diff --git a/docs/conf.py b/docs/conf.py
index 4ddee2b..e6e624a 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 #
-# python-pksc documentation build configuration file, created by
+# python-pskc documentation build configuration file, created by
 # sphinx-quickstart
 #
 # This file is execfile()d with the current directory set to its containing 
dir.
@@ -184,10 +184,12 @@ htmlhelp_basename = 'python-pskcdoc'
 # (source start file, name, description, authors, manual section).
 man_pages = [
     ('pskc2csv', 'pskc2csv', u'Convert a PSKC file to CSV',
-     [u'Arthur de Jong'], 1)
+     [u'Arthur de Jong'], 1),
+    ('pskc2pskc', 'pskc2pskc', u'Convert a PSKC file to standard format',
+     [u'Arthur de Jong'], 1),
 ]
 
 # If true, show URL addresses after external links.
 man_show_urls = True
 
-intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}
+#intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}
diff --git a/docs/pskc2pskc.rst b/docs/pskc2pskc.rst
new file mode 100644
index 0000000..6bce649
--- /dev/null
+++ b/docs/pskc2pskc.rst
@@ -0,0 +1,56 @@
+:orphan:
+
+pskc2pskc
+=========
+
+Synopsis
+--------
+
+**pskc2pskc** [*options*] <*FILE*>
+
+Description
+-----------
+
+:program:`pskc2pskc` reads a PSKC file in any of the supported formats,
+optionally decrypts any encrypted information and outputs a PSKC file in the
+RFC6030 format, optionally encrypting the file.
+
+Options
+-------
+
+.. program:: pskc2pskc
+
+.. option:: -h, --help
+
+   Display usage summary.
+
+.. option:: -V, --version
+
+   Display version information.
+
+.. option:: -o FILE, --output FILE
+
+   By default :program:`pskc2pskc` writes a PSKC file to stdout. This option
+   can be used to save to a file instead.
+
+.. option:: -p PASS/FILE, --password PASS/FILE, --passwd PASS/FILE
+
+   The password to use for decryption. If the argument refers to a file the
+   password is read from the file instead.
+
+.. option:: -s KEY/FILE, --secret KEY/FILE
+
+   A hex encoded encryption key or a file containing the binary (raw data,
+   not encoded) key used for decryption.
+
+.. option:: --new-password PASS/FILE, --new-passwd PASS/FILE
+
+   Output an encrypted PSKC file that is protected with the specified
+   password (or read the password from the file if a file argument was
+   specified).
+
+.. option:: --new-secret KEY/FILE
+
+   Ensure that the output PSKC file is encrypted with the specified key
+   value. The key can be probded as a hex-encoded value or point to a file
+   that contains the binary value of the key.
diff --git a/pskc2pskc.py b/pskc2pskc.py
new file mode 100755
index 0000000..282f4f9
--- /dev/null
+++ b/pskc2pskc.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+# coding: utf-8
+
+# pskc2pskc.py - script to convert a PSKC file to another PSKC file
+#
+# Copyright (C) 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
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+from __future__ import print_function
+import argparse
+import getpass
+import operator
+import os.path
+import sys
+from binascii import a2b_hex, b2a_hex
+
+import pskc
+
+
+version_string = '''
+pskc2pskc (python-pskc) %s
+Written by Arthur de Jong.
+
+Copyright (C) 2018 Arthur de Jong
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+'''.strip() % pskc.__version__
+
+
+class VersionAction(argparse.Action):
+
+    def __init__(self, option_strings, dest,
+                 help='output version information and exit'):
+        super(VersionAction, self).__init__(
+            option_strings=option_strings,
+            dest=argparse.SUPPRESS,
+            default=argparse.SUPPRESS,
+            nargs=0,
+            help=help)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        print(version_string)
+        parser.exit()
+
+
+epilog = '''
+supported columns:
+  id, serial, secret, counter, time_offset, time_interval, interval,
+  time_drift, issuer, manufacturer, response_length, algorithm
+And any other properties of pskc.key.Key instances.
+
+Report bugs to <python-pskc-users@lists.arthurdejong.org>.
+'''.strip()
+
+# set up command line parser
+parser = argparse.ArgumentParser(
+    formatter_class=argparse.RawDescriptionHelpFormatter,
+    description='Convert a PSKC file to another PSKC file.', epilog=epilog)
+parser.add_argument(
+    'input', metavar='FILE', help='the PSKC file to read')
+parser.add_argument(
+    '-V', '--version', action=VersionAction)
+parser.add_argument(
+    '-o', '--output', metavar='FILE',
+    help='write PSKC to file instead of stdout')
+parser.add_argument(
+    '-p', '--password', '--passwd', metavar='PASS/FILE',
+    help='password to use for decryption (or read from a file)')
+parser.add_argument(
+    '-s', '--secret', metavar='KEY/FILE',
+    help='hex encoded encryption key or a file containing the binary key')
+parser.add_argument(
+    '--new-password', '--new-passwd', metavar='PASS/FILE',
+    help='password to use for encryption (or read from a file)')
+parser.add_argument(
+    '--new-secret', metavar='KEY/FILE',
+    help='hex encoded encryption key or a file containing the binary key')
+
+
+def get_key(argument):
+    """Get the key from a file or a hex-encoded string."""
+    if os.path.isfile(argument):
+        with open(argument, 'rb') as keyfile:
+            return keyfile.read()
+    else:
+        return a2b_hex(argument)
+
+
+def get_password(argument):
+    """Get the password from a file or as a string."""
+    if os.path.isfile(argument):
+        with open(argument, 'r') as passfile:
+            return passfile.read().replace('\n', '')
+    else:
+        return argument
+
+
+def main():
+    # parse command-line arguments
+    args = parser.parse_args()
+    # open and parse input PSKC file
+    pskcfile = pskc.PSKC(args.input)
+    if args.secret:
+        pskcfile.encryption.key = get_key(args.secret)
+        pskcfile.encryption.remove_encryption()
+    elif args.password:
+        pskcfile.encryption.derive_key(get_password(args.password))
+        pskcfile.encryption.remove_encryption()
+    # encrypt the file if needed
+    if args.new_secret:
+        assert not pskcfile.encryption.is_encrypted
+        pskcfile.encryption.setup_preshared_key(key=get_key(args.new_secret))
+    elif args.new_password:
+        assert not pskcfile.encryption.is_encrypted
+        pskcfile.encryption.setup_pbkdf2(get_password(args.new_password))
+    # write output PSKC file
+    output = open(args.output, 'w') if args.output else sys.stdout
+    pskcfile.write(output)
+    if args.output:
+        output.close()
+    else:
+        output.flush()
+
+
+if __name__ == '__main__':  # pragma: no cover
+    main()
diff --git a/setup.cfg b/setup.cfg
index bdb061f..56f0c04 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -8,7 +8,7 @@ doctest-extension=doctest
 doctest-options=+IGNORE_EXCEPTION_DETAIL
 with-coverage=true
 cover-branches=true
-cover-package=pskc,pskc2csv
+cover-package=pskc,pskc2csv,pskc2pskc
 cover-inclusive=true
 cover-erase=true
 cover-html=true
diff --git a/tests/test_pskc2pskc.doctest b/tests/test_pskc2pskc.doctest
new file mode 100644
index 0000000..43eddd9
--- /dev/null
+++ b/tests/test_pskc2pskc.doctest
@@ -0,0 +1,371 @@
+test_pskc2pskc.doctest - tests for the pskc2pskc script
+
+Copyright (C) 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
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA
+
+
+>>> from binascii import a2b_hex
+>>> import shlex
+>>> import sys
+>>> import tempfile
+
+>>> from pskc import PSKC
+>>> from pskc2pskc import main
+
+
+Sadly we cannot test --help and --version properly because argparse calls
+exit(0) which doctest does not like.
+
+>>> sys.argv = shlex.split('pskc2pskc --help')
+>>> main()  # doctest: +IGNORE_EXCEPTION_DETAIL
+Traceback (most recent call last):
+    ...
+SystemExit: 0
+>>> sys.argv = shlex.split('pskc2pskc --version')
+>>> main()  # doctest: +IGNORE_EXCEPTION_DETAIL
+Traceback (most recent call last):
+    ...
+SystemExit: 0
+
+
+We can convert the PSKC file and just dump it to stdout.
+
+>>> sys.argv = shlex.split('pskc2pskc tests/rfc6030/figure2.pskcxml')
+>>> main()  #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc" 
Id="exampleID1" Version="1.0">
+ <pskc:KeyPackage>
+  <pskc:Key Algorithm="urn:ietf:params:xml:ns:keyprov:pskc:hotp" Id="12345678">
+   <pskc:Issuer>Issuer-A</pskc:Issuer>
+   <pskc:Data>
+    <pskc:Secret>
+     <pskc:PlainValue>MTIzNA==</pskc:PlainValue>
+    </pskc:Secret>
+   </pskc:Data>
+  </pskc:Key>
+ </pskc:KeyPackage>
+</pskc:KeyContainer>
+
+
+We can also save the output to a file.
+
+>>> f = tempfile.NamedTemporaryFile()
+>>> sys.argv = shlex.split(
+...     'pskc2pskc tests/rfc6030/figure2.pskcxml --output') + [f.name]
+>>> main()
+>>> with open(f.name, 'r') as r:
+...     x = sys.stdout.write(r.read())  #doctest: +REPORT_UDIFF 
+NORMALIZE_WHITESPACE
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc" 
Id="exampleID1" Version="1.0">
+ <pskc:KeyPackage>
+  <pskc:Key Algorithm="urn:ietf:params:xml:ns:keyprov:pskc:hotp" Id="12345678">
+   <pskc:Issuer>Issuer-A</pskc:Issuer>
+   <pskc:Data>
+    <pskc:Secret>
+     <pskc:PlainValue>MTIzNA==</pskc:PlainValue>
+    </pskc:Secret>
+   </pskc:Data>
+  </pskc:Key>
+ </pskc:KeyPackage>
+</pskc:KeyContainer>
+
+
+We can also re-write the file without decrypting the data at all.
+
+>>> sys.argv = shlex.split(
+...     'pskc2pskc tests/encryption/aes128-cbc.pskcxml')
+>>> main()  #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer xmlns:ds="http://www.w3.org/2000/09/xmldsig#"; 
xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc" 
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"; Version="1.0">
+ <pskc:EncryptionKey>
+  <ds:KeyName>Pre-shared-key</ds:KeyName>
+ </pskc:EncryptionKey>
+ <pskc:MACMethod 
Algorithm="http://www.w3.org/2001/04/xmldsig-more#hmac-sha224";>
+  <pskc:MACKey>
+   <xenc:EncryptionMethod 
Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
+   <xenc:CipherData>
+    
<xenc:CipherValue>SVZJVklWSVZJVklWSVZJViZS3d+rzbWqD74OQPuyiwrD+XlDXK7ef602mwOebfTR</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+cIHItlB3Wra1DUpxVvOx2lef1VmNPCMl8jwZqIUqGv</xenc:CipherValue>
+      </xenc:CipherData>
+     </pskc:EncryptedValue>
+     <pskc:ValueMAC>CjGsEXpmZYGMyejd8WJdLFRBWE9XGJLiigPObg==</pskc:ValueMAC>
+    </pskc:Secret>
+   </pskc:Data>
+  </pskc:Key>
+ </pskc:KeyPackage>
+</pskc:KeyContainer>
+
+
+This should also work with legacy PSKC files that have a global encryption
+IV. The output file should be a clean PSKC 1.0 format with the IV embedded in
+the CipherValue. Note however that the MAC key is missing because it is equal
+to the encryption key so we cannot make en encrypted version.
+
+>>> sys.argv = shlex.split(
+...     'pskc2pskc tests/actividentity/test.pskcxml')
+>>> main()  #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc" 
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"; Version="1.0">
+ <pskc:MACMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"/>
+ <pskc:KeyPackage>
+  <pskc:DeviceInfo>
+   <pskc:Manufacturer>ActivIdentity</pskc:Manufacturer>
+   <pskc:SerialNo>0950380269</pskc:SerialNo>
+  </pskc:DeviceInfo>
+  <pskc:Key Algorithm="http://www.ietf.org/keyprov/pskc#hotp"; Id="0950380269">
+   <pskc:Issuer>ActivIdentity</pskc:Issuer>
+   <pskc:AlgorithmParameters>
+    <pskc:ResponseFormat Encoding="DECIMAL" Length="8"/>
+   </pskc:AlgorithmParameters>
+   <pskc:Data>
+    <pskc:Secret>
+     <pskc:EncryptedValue>
+      <xenc:EncryptionMethod 
Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
+      <xenc:CipherData>
+       
<xenc:CipherValue>Xus0lsc+rJLi0nc/ANE0XtRwSU4Zs2AwlO2AqzC+jmSjLEUK4kr2aaKnjHwbovXS</xenc:CipherValue>
+      </xenc:CipherData>
+     </pskc:EncryptedValue>
+     <pskc:ValueMAC>SlinEB9YUzcR04MUZDF5dBLtK1c=</pskc:ValueMAC>
+    </pskc:Secret>
+    <pskc:Counter>
+     <pskc:PlainValue>837830147</pskc:PlainValue>
+    </pskc:Counter>
+   </pskc:Data>
+   <pskc:Policy>
+    <pskc:KeyUsage>OTP</pskc:KeyUsage>
+   </pskc:Policy>
+  </pskc:Key>
+ </pskc:KeyPackage>
+</pskc:KeyContainer>
+
+
+We can also output a decrypted version of an encrypted PSKC file.
+
+>>> sys.argv = shlex.split(
+...     'pskc2pskc 
tests/draft-hoyer-keyprov-portable-symmetric-key-container-00/password-encrypted.pskcxml'
 +
+...     ' --passwd qwerty')
+>>> main()  #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc" 
Version="1.0">
+ <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:PlainValue>ZWcLvpFoXNHAG+lx3+Rw</pskc:PlainValue>
+    </pskc:Secret>
+    <pskc:Counter>
+     <pskc:PlainValue>100</pskc:PlainValue>
+    </pskc:Counter>
+   </pskc:Data>
+  </pskc:Key>
+ </pskc:KeyPackage>
+</pskc:KeyContainer>
+
+
+The password can also be read from a file.
+
+>>> f = tempfile.NamedTemporaryFile()
+>>> with open(f.name, 'wt') as f2:  # open second file to keep tempfile
+...     x = f2.write('qwerty\n')
+>>> sys.argv = shlex.split(
+...     'pskc2pskc 
tests/draft-hoyer-keyprov-portable-symmetric-key-container-00/password-encrypted.pskcxml'
 +
+...     ' --passwd') + [f.name]
+>>> main()  #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc" 
Version="1.0">
+ <pskc:KeyPackage>
+...
+   <pskc:Data>
+    <pskc:Secret>
+     <pskc:PlainValue>ZWcLvpFoXNHAG+lx3+Rw</pskc:PlainValue>
+    </pskc:Secret>
+...
+ </pskc:KeyPackage>
+</pskc:KeyContainer>
+
+
+But we get an error if the password is wrong.
+
+>>> sys.argv = shlex.split(
+...     'pskc2pskc 
tests/draft-hoyer-keyprov-portable-symmetric-key-container-00/password-encrypted.pskcxml'
 +
+...     ' --passwd wrongpassword')
+>>> main()  #doctest: +ELLIPSIS
+Traceback (most recent call last):
+    ...
+DecryptionError: ...
+
+
+We can also supply a secret (both on the command line and via a file).
+
+>>> sys.argv = shlex.split(
+...     'pskc2csv tests/rfc6030/figure6.pskcxml' +
+...     ' --secret 12345678901234567890123456789012')
+>>> main()  #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer ... Version="1.0">
+ <pskc:KeyPackage>
+...
+   <pskc:Data>
+    <pskc:Secret>
+     <pskc:PlainValue>MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=</pskc:PlainValue>
+    </pskc:Secret>
+...
+ </pskc:KeyPackage>
+</pskc:KeyContainer>
+>>> sys.argv = shlex.split(
+...     'pskc2csv tests/rfc6030/figure6.pskcxml' +
+...     ' --secret 12345678901234567890123456789012')
+>>> main()  #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer ... Version="1.0">
+ <pskc:KeyPackage>
+...
+   <pskc:Data>
+    <pskc:Secret>
+     <pskc:PlainValue>MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=</pskc:PlainValue>
+    </pskc:Secret>
+...
+ </pskc:KeyPackage>
+</pskc:KeyContainer>
+>>> f = tempfile.NamedTemporaryFile()
+>>> with open(f.name, 'wb') as f2:  # open second file to keep tempfile
+...     x = f2.write(a2b_hex('12345678901234567890123456789012'))
+>>> sys.argv = shlex.split(
+...     'pskc2csv tests/rfc6030/figure6.pskcxml' +
+...     ' --secret') + [f.name]
+>>> main()  #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer ... Version="1.0">
+ <pskc:KeyPackage>
+...
+   <pskc:Data>
+    <pskc:Secret>
+     <pskc:PlainValue>MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=</pskc:PlainValue>
+    </pskc:Secret>
+...
+ </pskc:KeyPackage>
+</pskc:KeyContainer>
+
+
+We can also decrypt a file and configure a new passphrase.
+
+>>> sys.argv = shlex.split(
+...     'pskc2pskc 
tests/draft-hoyer-keyprov-portable-symmetric-key-container-00/password-encrypted.pskcxml'
 +
+...     ' --passwd qwerty --new-passwd moresecure')
+>>> main()  #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc" 
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"; 
xmlns:xenc11="http://www.w3.org/2009/xmlenc11#"; 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>...</Specified>
+     </Salt>
+     <IterationCount>12000</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#aes128-cbc"/>
+   <xenc:CipherData>
+    <xenc:CipherValue>...</xenc:CipherValue>
+   </xenc:CipherData>
+  </pskc:MACKey>
+ </pskc:MACMethod>
+ <pskc:KeyPackage>
+...
+    <pskc:Secret>
+     <pskc:EncryptedValue>
+      <xenc:EncryptionMethod 
Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
+      <xenc:CipherData>
+       <xenc:CipherValue>...</xenc:CipherValue>
+      </xenc:CipherData>
+     </pskc:EncryptedValue>
+     <pskc:ValueMAC>...</pskc:ValueMAC>
+    </pskc:Secret>
+...
+ </pskc:KeyPackage>
+</pskc:KeyContainer>
+
+
+Alternatively we can switch from passphrase-based encryption to key-based
+encryption.
+
+>>> sys.argv = shlex.split(
+...     'pskc2pskc 
tests/draft-hoyer-keyprov-portable-symmetric-key-container-00/password-encrypted.pskcxml'
 +
+...     ' --passwd qwerty --new-secret 12345678901234567890123456789012')
+>>> main()  #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc" 
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"; 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>...</xenc:CipherValue>
+   </xenc:CipherData>
+  </pskc:MACKey>
+ </pskc:MACMethod>
+ <pskc:KeyPackage>
+...
+    <pskc:Secret>
+     <pskc:EncryptedValue>
+      <xenc:EncryptionMethod 
Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
+      <xenc:CipherData>
+       <xenc:CipherValue>...</xenc:CipherValue>
+      </xenc:CipherData>
+     </pskc:EncryptedValue>
+     <pskc:ValueMAC>...</pskc:ValueMAC>
+    </pskc:Secret>
+...
+ </pskc:KeyPackage>
+</pskc:KeyContainer>
+
+
+If we leave out the original password we get an error.
+
+>>> sys.argv = shlex.split(
+...     'pskc2pskc 
tests/draft-hoyer-keyprov-portable-symmetric-key-container-00/password-encrypted.pskcxml'
 +
+...     ' --new-passwd moresecure')
+>>> main()  #doctest: +ELLIPSIS
+Traceback (most recent call last):
+    ...
+AssertionError

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

Summary of changes:
 docs/conf.py                 |   8 +-
 docs/pskc2pskc.rst           |  56 +++++++
 pskc2csv.py => pskc2pskc.py  |  95 +++++------
 setup.cfg                    |   2 +-
 tests/test_pskc2pskc.doctest | 371 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 474 insertions(+), 58 deletions(-)
 create mode 100644 docs/pskc2pskc.rst
 copy pskc2csv.py => pskc2pskc.py (55%)
 create mode 100644 tests/test_pskc2pskc.doctest


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/