python-pskc branch master updated. 0.2-6-g480e2d0
[
Date Prev][
Date Next]
[
Thread Prev][
Thread Next]
python-pskc branch master updated. 0.2-6-g480e2d0
- From: Commits of the python-pskc project <python-pskc-commits [at] lists.arthurdejong.org>
- To: python-pskc-commits [at] lists.arthurdejong.org
- Reply-to: python-pskc-users [at] lists.arthurdejong.org
- Subject: python-pskc branch master updated. 0.2-6-g480e2d0
- Date: Sat, 28 Jun 2014 22:52:30 +0200 (CEST)
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 480e2d0efeba8fb916b9d4e96a196786e59acad8 (commit)
via 37dc64ade0ccff0ba9c33ccbf976935b73ffa7a1 (commit)
via 865a755e28d0273b2edd7d192802e8ac216074d6 (commit)
via 61a192f40e95cb986c1cebee4a7005aae83a2dc0 (commit)
via 69aec9fd56f7aa67db1c2a24ff3551af5fc1f012 (commit)
via 7591271f9d8bebd7a5fa7feaa6b3e84a263eb1ca (commit)
from 09eb6b333c5a81392b70255db637be669d511654 (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 -----------------------------------------------------------------
http://arthurdejong.org/git/python-pskc/commit/?id=480e2d0efeba8fb916b9d4e96a196786e59acad8
commit 480e2d0efeba8fb916b9d4e96a196786e59acad8
Merge: 7591271 37dc64a
Author: Arthur de Jong <arthur@arthurdejong.org>
Date: Sat Jun 28 22:47:31 2014 +0200
Support writing unencrypted PSKC files
http://arthurdejong.org/git/python-pskc/commit/?id=37dc64ade0ccff0ba9c33ccbf976935b73ffa7a1
commit 37dc64ade0ccff0ba9c33ccbf976935b73ffa7a1
Author: Arthur de Jong <arthur@arthurdejong.org>
Date: Fri Jun 27 14:34:23 2014 +0200
Add test for writing PSKC files
This makes a simple doctest that checks the writing of the XML
representation of the PSKC data.
diff --git a/tests/test_write.doctest b/tests/test_write.doctest
new file mode 100644
index 0000000..0d91eb6
--- /dev/null
+++ b/tests/test_write.doctest
@@ -0,0 +1,143 @@
+test_write.doctest - tests for writing PSKC files
+
+Copyright (C) 2014 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
+
+>>> import datetime
+>>> import sys
+>>> import tempfile
+>>> from dateutil.tz import tzutc
+>>> utc = tzutc()
+
+>>> from pskc import PSKC
+
+
+Build a PSKC structure.
+
+>>> pskc = PSKC()
+
+
+Add a key with all attributes set.
+
+>>> key = pskc.add_key(id='456', manufacturer='Manufacturer')
+>>> key.id = '123'
+>>> key.serial = '987654321'
+>>> key.model = 'Model'
+>>> key.issue_no = 2
+>>> key.start_date = datetime.datetime(2006, 5, 1, 0, 0, tzinfo=utc)
+>>> key.expiry_date = datetime.datetime(2014, 5, 31, 0, 0, tzinfo=utc)
+>>> key.device_userid = 'uid=arthur, dc=arthurdejong, dc=org'
+>>> key.crypto_module = 'CyrptoId'
+>>> key.algorithm = 'urn:ietf:params:xml:ns:keyprov:pskc:totp'
+>>> key.issuer = 'Issuer'
+>>> key.key_profile = 'key profile id'
+>>> key.key_reference = 'reference to some key'
+>>> key.friendly_name = 'a friendly key'
+>>> key.key_userid = 'cn=Arthur de Jong, dc=arthurdejong, dc=org'
+>>> key.algorithm_suite = 'Clubs'
+>>> key.challenge_encoding = 'DECIMAL'
+>>> key.challenge_min_length = 6
+>>> key.challenge_max_length = 8
+>>> key.challenge_check = True
+>>> key.response_encoding = 'DECIMAL'
+>>> key.response_length = 8
+>>> key.response_check = False
+>>> key.counter = 0
+>>> key.secret = '4e1790ba272406ba309c5a31'.decode('hex')
+
+
+Add policy information and a PIN.
+
+>>> key.policy.key_usage.append('OTP')
+>>> key.policy.key_usage.append(key.policy.KEY_USE_VERIFY)
+>>> key.policy.start_date = datetime.datetime(2008, 5, 1, 0, 0, tzinfo=utc)
+>>> key.policy.expiry_date = datetime.datetime(2012, 6, 13, 0, 0, tzinfo=utc)
+>>> key.policy.number_of_transactions = 42
+>>> key.policy.pin_key_id = 'pinID'
+>>> key.policy.pin_usage = 'Local'
+>>> key.policy.pin_max_failed_attemtps = 3
+>>> key.policy.pin_min_length = 4
+>>> key.policy.pin_max_length = 4
+>>> key.policy.pin_encoding = 'DECIMAL'
+>>> pin_key = pskc.add_key(id='pinID', secret='1234',
+... algorithm='urn:ietf:params:xml:ns:keyprov:pskc:pin',
+... response_encoding='DECIMAL', response_length=4)
+
+
+Write the PSKC file (use temporary file to test passing file name as
+argument).
+
+>>> f = tempfile.NamedTemporaryFile()
+>>> pskc.write(f.name)
+>>> sys.stdout.write(open(f.name, 'rb').read())
+<?xml version="1.0" encoding="UTF-8"?>
+<pskc:KeyContainer Version="1.0"
xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc">
+ <pskc:KeyPackage>
+ <pskc:DeviceInfo>
+ <pskc:Manufacturer>Manufacturer</pskc:Manufacturer>
+ <pskc:SerialNo>987654321</pskc:SerialNo>
+ <pskc:Model>Model</pskc:Model>
+ <pskc:IssueNo>2</pskc:IssueNo>
+ <pskc:StartDate>2006-05-01T00:00:00Z</pskc:StartDate>
+ <pskc:ExpiryDate>2014-05-31T00:00:00Z</pskc:ExpiryDate>
+ <pskc:UserId>uid=arthur, dc=arthurdejong, dc=org</pskc:UserId>
+ </pskc:DeviceInfo>
+ <pskc:CryptoModuleInfo>
+ <pskc:Id>CyrptoId</pskc:Id>
+ </pskc:CryptoModuleInfo>
+ <pskc:Key Algorithm="urn:ietf:params:xml:ns:keyprov:pskc:totp" Id="123">
+ <pskc:Issuer>Issuer</pskc:Issuer>
+ <pskc:AlgorithmParameters>
+ <pskc:Suite>Clubs</pskc:Suite>
+ <pskc:ChallengeFormat CheckDigits="true" Encoding="DECIMAL" Max="8"
Min="6"/>
+ <pskc:ResponseFormat CheckDigits="false" Encoding="DECIMAL" Length="8"/>
+ </pskc:AlgorithmParameters>
+ <pskc:KeyProfileId>key profile id</pskc:KeyProfileId>
+ <pskc:KeyReference>reference to some key</pskc:KeyReference>
+ <pskc:FriendlyName>a friendly key</pskc:FriendlyName>
+ <pskc:Data>
+ <pskc:Secret>
+ <pskc:PlainValue>TheQuickBrownFox</pskc:PlainValue>
+ </pskc:Secret>
+ <pskc:Counter>
+ <pskc:PlainValue>0</pskc:PlainValue>
+ </pskc:Counter>
+ </pskc:Data>
+ <pskc:UserId>cn=Arthur de Jong, dc=arthurdejong, dc=org</pskc:UserId>
+ <pskc:Policy>
+ <pskc:StartDate>2008-05-01T00:00:00Z</pskc:StartDate>
+ <pskc:ExpiryDate>2012-06-13T00:00:00Z</pskc:ExpiryDate>
+ <pskc:PINPolicy MaxFailedAttempts="3" MaxLength="4" MinLength="4"
PINEncoding="DECIMAL" PINKeyId="pinID" PINUsageMode="Local"/>
+ <pskc:KeyUsage>OTP</pskc:KeyUsage>
+ <pskc:KeyUsage>Verify</pskc:KeyUsage>
+ <pskc:NumberOfTransactions>42</pskc:NumberOfTransactions>
+ </pskc:Policy>
+ </pskc:Key>
+ </pskc:KeyPackage>
+ <pskc:KeyPackage>
+ <pskc:Key Algorithm="urn:ietf:params:xml:ns:keyprov:pskc:pin" Id="pinID">
+ <pskc:AlgorithmParameters>
+ <pskc:ResponseFormat Encoding="DECIMAL" Length="4"/>
+ </pskc:AlgorithmParameters>
+ <pskc:Data>
+ <pskc:Secret>
+ <pskc:PlainValue>MTIzNA==</pskc:PlainValue>
+ </pskc:Secret>
+ </pskc:Data>
+ </pskc:Key>
+ </pskc:KeyPackage>
+</pskc:KeyContainer>
http://arthurdejong.org/git/python-pskc/commit/?id=865a755e28d0273b2edd7d192802e8ac216074d6
commit 865a755e28d0273b2edd7d192802e8ac216074d6
Author: Arthur de Jong <arthur@arthurdejong.org>
Date: Fri Jun 27 16:27:54 2014 +0200
Add function for writing XML
This provides a function for pretty-printing the generated XML document.
diff --git a/pskc/__init__.py b/pskc/__init__.py
index 4a33d42..7c9e2da 100644
--- a/pskc/__init__.py
+++ b/pskc/__init__.py
@@ -124,3 +124,12 @@ class PSKC(object):
raise AttributeError()
setattr(key, k, v)
return key
+
+ def write(self, filename):
+ """Write the PSKC file to the provided file."""
+ from pskc.parse import tostring
+ if hasattr(filename, 'write'):
+ filename.write(tostring(self.make_xml()))
+ else:
+ with open(filename, 'wb') as output:
+ self.write(output)
diff --git a/pskc/parse.py b/pskc/parse.py
index a853ce5..98839ad 100644
--- a/pskc/parse.py
+++ b/pskc/parse.py
@@ -148,3 +148,11 @@ def mk_elem(parent, tag=None, text=None, empty=False,
**kwargs):
if v is not None:
element.set(k, _format(v))
return element
+
+
+def tostring(element):
+ """Return a serialised XML document for the element tree."""
+ from xml.dom import minidom
+ xml = etree.tostring(element, encoding='UTF-8')
+ return minidom.parseString(xml).toprettyxml(
+ indent=' ', encoding='UTF-8').strip()
http://arthurdejong.org/git/python-pskc/commit/?id=61a192f40e95cb986c1cebee4a7005aae83a2dc0
commit 61a192f40e95cb986c1cebee4a7005aae83a2dc0
Author: Arthur de Jong <arthur@arthurdejong.org>
Date: Fri Jun 27 14:24:02 2014 +0200
Construct XML document with basic PKSC information
This introduces make_xml() functions to build an XML document that
contains the basic PSKC information and keys. This currently only
supports writing unencrypted PSKC files.
diff --git a/pskc/__init__.py b/pskc/__init__.py
index 61fa9fe..4a33d42 100644
--- a/pskc/__init__.py
+++ b/pskc/__init__.py
@@ -102,6 +102,14 @@ class PSKC(object):
for key_package in findall(container, 'pskc:KeyPackage'):
self.keys.append(Key(self, key_package))
+ def make_xml(self):
+ from pskc.parse import mk_elem
+ container = mk_elem('pskc:KeyContainer', Version=self.version,
+ Id=self.id)
+ for key in self.keys:
+ key.make_xml(container)
+ return container
+
def add_key(self, **kwargs):
"""Create a new key instance for the PSKC file.
diff --git a/pskc/key.py b/pskc/key.py
index 9ed79d4..1814a48 100644
--- a/pskc/key.py
+++ b/pskc/key.py
@@ -60,6 +60,19 @@ class DataType(object):
self.encrypted_value.parse(find(element, 'pskc:EncryptedValue'))
self.value_mac.parse(find(element, 'pskc:ValueMAC'))
+ def make_xml(self, key, tag):
+ from pskc.parse import find, mk_elem
+ # skip empty values
+ value = self.get_value()
+ if value is None:
+ return
+ # find the data tag and create our tag under it
+ data = find(key, 'pskc:Data')
+ if data is None:
+ data = mk_elem(key, 'pskc:Data', empty=True)
+ element = mk_elem(data, tag, empty=True)
+ mk_elem(element, 'pskc:PlainValue', self.to_text(self.value))
+
def get_value(self):
"""Provide the raw binary value."""
if self.value is not None:
@@ -87,6 +100,10 @@ class BinaryDataType(DataType):
"""Convert the plain value to native representation."""
return base64.b64decode(value)
+ def to_text(self, value):
+ """Convert the value to an unencrypted string representation."""
+ return base64.b64encode(value)
+
def from_bin(self, value):
"""Convert the unencrypted binary to native representation."""
return value
@@ -99,6 +116,10 @@ class IntegerDataType(DataType):
"""Convert the plain value to native representation."""
return int(value)
+ def to_text(self, value):
+ """Convert the value to an unencrypted string representation."""
+ return str(value)
+
def from_bin(self, value):
"""Convert the unencrypted binary to native representation."""
result = 0
@@ -256,6 +277,60 @@ class Key(object):
self.policy.parse(find(key_package, 'pskc:Key/pskc:Policy'))
+ def make_xml(self, container):
+ from pskc.parse import mk_elem
+
+ key_package = mk_elem(container, 'pskc:KeyPackage', empty=True)
+
+ if any(x is not None
+ for x in (self.manufacturer, self.serial, self.model,
+ self.issue_no, self.device_binding, self.start_date,
+ self.expiry_date, self.device_userid)):
+ device_info = mk_elem(key_package, 'pskc:DeviceInfo', empty=True)
+ mk_elem(device_info, 'pskc:Manufacturer', self.manufacturer)
+ mk_elem(device_info, 'pskc:SerialNo', self.serial)
+ mk_elem(device_info, 'pskc:Model', self.model)
+ mk_elem(device_info, 'pskc:IssueNo', self.issue_no)
+ mk_elem(device_info, 'pskc:DeviceBinding', self.device_binding)
+ mk_elem(device_info, 'pskc:StartDate', self.start_date)
+ mk_elem(device_info, 'pskc:ExpiryDate', self.expiry_date)
+ mk_elem(device_info, 'pskc:UserId', self.device_userid)
+
+ if self.crypto_module is not None:
+ crypto_module = mk_elem(key_package, 'pskc:CryptoModuleInfo',
+ empty=True)
+ mk_elem(crypto_module, 'pskc:Id', self.crypto_module)
+
+ key = mk_elem(key_package, 'pskc:Key', empty=True, Id=self.id,
+ Algorithm=self.algorithm, )
+ mk_elem(key, 'pskc:Issuer', self.issuer)
+
+ if any((self.algorithm_suite, self.challenge_encoding,
+ self.response_encoding, self.response_length)):
+ parameters = mk_elem(key, 'pskc:AlgorithmParameters', empty=True)
+ mk_elem(parameters, 'pskc:Suite', self.algorithm_suite)
+ mk_elem(parameters, 'pskc:ChallengeFormat',
+ Encoding=self.challenge_encoding,
+ Min=self.challenge_min_length,
+ Max=self.challenge_max_length,
+ CheckDigits=self.challenge_check)
+ mk_elem(parameters, 'pskc:ResponseFormat',
+ Encoding=self.response_encoding,
+ Length=self.response_length,
+ CheckDigits=self.response_check)
+
+ mk_elem(key, 'pskc:KeyProfileId', self.key_profile)
+ mk_elem(key, 'pskc:KeyReference', self.key_reference)
+ mk_elem(key, 'pskc:FriendlyName', self.friendly_name)
+ self._secret.make_xml(key, 'pskc:Secret')
+ self._counter.make_xml(key, 'pskc:Counter')
+ self._time_offset.make_xml(key, 'pskc:Time')
+ self._time_interval.make_xml(key, 'pskc:TimeInterval')
+ self._time_drift.make_xml(key, 'pskc:TimeDrift')
+ mk_elem(key, 'pskc:UserId', self.key_userid)
+
+ self.policy.make_xml(key)
+
secret = property(
fget=lambda self: self._secret.get_value(),
fset=lambda self, x: self._secret.set_value(x),
diff --git a/pskc/policy.py b/pskc/policy.py
index ee0095e..f1d976c 100644
--- a/pskc/policy.py
+++ b/pskc/policy.py
@@ -136,6 +136,32 @@ class Policy(object):
# TODO: check if there are other children and make sure
# policy rejects any key usage (set unknown_policy_elements)
+ def make_xml(self, key):
+ from pskc.parse import mk_elem
+ # check if any policy attribute is set
+ if not self.key_usage and all(x is None for x in (
+ self.start_date, self.expiry_date,
+ self.number_of_transactions, self.pin_key_id, self.pin_usage,
+ self.pin_max_failed_attemtps, self.pin_min_length,
+ self.pin_max_length, self.pin_encoding)):
+ return
+ # TODO: raise exception if unknown_policy_elements is set
+
+ policy = mk_elem(key, 'pskc:Policy', empty=True)
+ mk_elem(policy, 'pskc:StartDate', self.start_date)
+ mk_elem(policy, 'pskc:ExpiryDate', self.expiry_date)
+ mk_elem(policy, 'pskc:PINPolicy',
+ PINKeyId=self.pin_key_id,
+ PINUsageMode=self.pin_usage,
+ MaxFailedAttempts=self.pin_max_failed_attemtps,
+ MinLength=self.pin_min_length,
+ MaxLength=self.pin_max_length,
+ PINEncoding=self.pin_encoding)
+ for usage in self.key_usage:
+ mk_elem(policy, 'pskc:KeyUsage', usage)
+ mk_elem(policy, 'pskc:NumberOfTransactions',
+ self.number_of_transactions)
+
def may_use(self, usage):
"""Check whether the key may be used for the provided purpose."""
if self.unknown_policy_elements:
http://arthurdejong.org/git/python-pskc/commit/?id=69aec9fd56f7aa67db1c2a24ff3551af5fc1f012
commit 69aec9fd56f7aa67db1c2a24ff3551af5fc1f012
Author: Arthur de Jong <arthur@arthurdejong.org>
Date: Fri Jun 27 11:39:28 2014 +0200
Introduce mk_elem() to create elements
This introduces the mk_elem() function that can be used to create
ElementTree elements for building XML documents. This function
transparetly handles namespaces, translation of values into XML etc.
diff --git a/pskc/parse.py b/pskc/parse.py
index a08bfc1..a853ce5 100644
--- a/pskc/parse.py
+++ b/pskc/parse.py
@@ -45,6 +45,11 @@ namespaces = dict(
)
+# register the namespaces so the correct short names will be used
+for ns, namespace in namespaces.items():
+ etree.register_namespace(ns, namespace)
+
+
def findall(tree, match):
"""Find a child element (or None)."""
return tree.findall(match, namespaces=namespaces)
@@ -100,3 +105,46 @@ def getbool(tree, attribute):
value = tree.get(attribute)
if value:
return value.lower() == 'true'
+
+
+def _format(value):
+ import datetime
+ if isinstance(value, datetime.datetime):
+ value = value.isoformat()
+ if value.endswith('+00:00'):
+ value = value[:-6] + 'Z'
+ return value
+ elif value is True:
+ return 'true'
+ elif value is False:
+ return 'false'
+ return str(value)
+
+
+def mk_elem(parent, tag=None, text=None, empty=False, **kwargs):
+ """Add element as a child of parent."""
+ # special-case the top-level element
+ if tag is None:
+ tag = parent
+ parent = None
+ empty = True
+ # don't create empty elements
+ if not empty and text is None and \
+ all(x is None for x in kwargs.itervalues()):
+ return
+ # replace namespace identifier with URL
+ if ':' in tag:
+ ns, name = tag.split(':', 1)
+ tag = '{%s}%s' % (namespaces[ns], name)
+ if parent is None:
+ element = etree.Element(tag)
+ else:
+ element = etree.SubElement(parent, tag)
+ # set text of element
+ if text is not None:
+ element.text = _format(text)
+ # set kwargs as attributes
+ for k, v in kwargs.iteritems():
+ if v is not None:
+ element.set(k, _format(v))
+ return element
http://arthurdejong.org/git/python-pskc/commit/?id=7591271f9d8bebd7a5fa7feaa6b3e84a263eb1ca
commit 7591271f9d8bebd7a5fa7feaa6b3e84a263eb1ca
Author: Arthur de Jong <arthur@arthurdejong.org>
Date: Fri Jun 27 22:19:32 2014 +0200
Simplify DataType value handling
Only store the native value of the property, not the text
representation. This also results in the BinaryDataType and
IntegerDataType subclasses only needing from_text() and from_bin()
functions.
diff --git a/pskc/key.py b/pskc/key.py
index 1eabdb1..9ed79d4 100644
--- a/pskc/key.py
+++ b/pskc/key.py
@@ -34,13 +34,13 @@ class DataType(object):
This class is meant to be subclassed to provide typed access to stored
values. Instances of this class provide the following attributes:
- plain_value: raw unencrypted value if present (possibly base64 encoded)
+ value: unencrypted value if present
encrypted_value: reference to an EncryptedValue instance
value_mac: reference to a ValueMAC instance
"""
def __init__(self, key, element=None):
- self.plain_value = None
+ self.value = None
self.encrypted_value = EncryptedValue(key.pskc.encryption)
self.value_mac = ValueMAC(key.pskc.mac)
self.parse(element)
@@ -54,13 +54,24 @@ class DataType(object):
from pskc.parse import find, findtext
if element is None:
return
- self.plain_value = findtext(element, 'pskc:PlainValue')
+ value = findtext(element, 'pskc:PlainValue')
+ if value is not None:
+ self.value = self.from_text(value)
self.encrypted_value.parse(find(element, 'pskc:EncryptedValue'))
self.value_mac.parse(find(element, 'pskc:ValueMAC'))
+ def get_value(self):
+ """Provide the raw binary value."""
+ if self.value is not None:
+ return self.value
+ if self.encrypted_value.cipher_value:
+ # check MAC and decrypt
+ self.check()
+ return self.from_bin(self.encrypted_value.decrypt())
+
def set_value(self, value):
- """Save the plain value."""
- self.plain_value = self.to_plain(value)
+ """Set the unencrypted value."""
+ self.value = value
self.encrypted_value.cipher_value = None
def check(self):
@@ -72,45 +83,28 @@ class DataType(object):
class BinaryDataType(DataType):
"""Subclass of DataType for binary data (e.g. keys)."""
- def get_value(self):
- """Provide the raw binary value."""
- # plain value is base64 encoded
- if self.plain_value is not None:
- return base64.b64decode(self.plain_value)
- # check MAC if present
- self.check()
- # encrypted value is in correct format
- return self.encrypted_value.decrypt()
+ def from_text(self, value):
+ """Convert the plain value to native representation."""
+ return base64.b64decode(value)
- def to_plain(self, value):
- """Convert the value to an unencrypted string representation."""
- if value:
- return base64.b64encode(value)
+ def from_bin(self, value):
+ """Convert the unencrypted binary to native representation."""
+ return value
class IntegerDataType(DataType):
"""Subclass of DataType for integer types (e.g. counters)."""
- def get_value(self):
- """Provide the raw integer value."""
- # plain value is a string representation of the number
- if self.plain_value:
- return int(self.plain_value)
- # check MAC if present
- self.check()
- # decrypted value is big endian encoded
- value = self.encrypted_value.decrypt()
- if value is not None:
- # Python3 has int.from_bytes(value, byteorder='big')
- v = 0
- for x in value:
- v = (v << 8) + ord(x)
- return v
-
- def to_plain(self, value):
- """Convert the value to an unencrypted string representation."""
- if value not in (None, ''):
- return str(value)
+ def from_text(self, value):
+ """Convert the plain value to native representation."""
+ return int(value)
+
+ def from_bin(self, value):
+ """Convert the unencrypted binary to native representation."""
+ result = 0
+ for x in value:
+ result = (result << 8) + ord(x)
+ return result
class Key(object):
-----------------------------------------------------------------------
Summary of changes:
pskc/__init__.py | 17 ++++++
pskc/key.py | 141 +++++++++++++++++++++++++++++++++------------
pskc/parse.py | 56 ++++++++++++++++++
pskc/policy.py | 26 +++++++++
tests/test_write.doctest | 143 ++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 347 insertions(+), 36 deletions(-)
create mode 100644 tests/test_write.doctest
hooks/post-receive
--
python-pskc
--
To unsubscribe send an email to
python-pskc-commits-unsubscribe@lists.arthurdejong.org or see
http://lists.arthurdejong.org/python-pskc-commits/
- python-pskc branch master updated. 0.2-6-g480e2d0,
Commits of the python-pskc project