Security updates.
authorstephendenham <stephendenham@2dec19e3-eb1d-4749-8193-008c8bba0994>
Wed, 24 Aug 2011 19:57:28 +0000 (19:57 +0000)
committerstephendenham <stephendenham@2dec19e3-eb1d-4749-8193-008c8bba0994>
Wed, 24 Aug 2011 19:57:28 +0000 (19:57 +0000)
git-svn-id: svn://svn.code.sf.net/p/xbmc-groove/code@51 2dec19e3-eb1d-4749-8193-008c8bba0994

.pydevproject
addon.xml
changelog.txt
description.xml
resources/lib/GroovesharkAPI.py
resources/lib/blowfish/__init__.py [new file with mode: 0644]
resources/lib/uuid/__init__.py [deleted file]

index 7848f52..01c7a69 100644 (file)
@@ -8,6 +8,7 @@
 <path>/xbmc-groove</path>
 <path>/xbmc-groove/resources/lib</path>
 <path>/xbmc-groove/resources/lib/simplejson</path>
 <path>/xbmc-groove</path>
 <path>/xbmc-groove/resources/lib</path>
 <path>/xbmc-groove/resources/lib/simplejson</path>
+<path>/xbmc-groove/resources/lib/blowfish</path>
 </pydev_pathproperty>
 
 </pydev_project>
 </pydev_pathproperty>
 
 </pydev_project>
index 5e25c0a..133e35d 100644 (file)
--- a/addon.xml
+++ b/addon.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <addon id="plugin.audio.groove" name="Grooveshark XBMC"
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <addon id="plugin.audio.groove" name="Grooveshark XBMC"
-       version="0.5.2" provider-name="Stephen Denham">
+       version="0.5.3" provider-name="Stephen Denham">
        <requires>
                <import addon="xbmc.python" version="1.0" />
        </requires>
        <requires>
                <import addon="xbmc.python" version="1.0" />
        </requires>
index 9c1015d..c8bc4a8 100644 (file)
@@ -1,3 +1,7 @@
+0.5.3
+
+Improve app engine security.
+
 0.5.2
 
 Use google app engine to serve requests.
 0.5.2
 
 Use google app engine to serve requests.
index bf543e0..95754d9 100644 (file)
@@ -18,7 +18,7 @@
        <title>Grooveshark XBMC</title>
 
        <!-- (required) Major.minor.build -->
        <title>Grooveshark XBMC</title>
 
        <!-- (required) Major.minor.build -->
-       <version>0.5.2</version>
+       <version>0.5.3</version>
 
        <!--
                (required) author name & email. at least one author name is required
 
        <!--
                (required) author name & email. at least one author name is required
index 0c09e25..43db1ba 100644 (file)
@@ -1,4 +1,5 @@
-import socket, hmac, urllib, urllib2, pprint, md5, os, pickle, tempfile, time, re, simplejson
+import socket, urllib, urllib2, pprint, md5, os, pickle, tempfile, time, re, simplejson, base64
+from blowfish import Blowfish
 
 SESSION_EXPIRY = 1209600 # 2 weeks
 
 
 SESSION_EXPIRY = 1209600 # 2 weeks
 
@@ -22,6 +23,7 @@ class GrooveAPI:
        _lastSessionTime = 0
        _lastStreamKey = ''
        _lastStreamServerID = ''
        _lastSessionTime = 0
        _lastStreamKey = ''
        _lastStreamServerID = ''
+       _key = md5.new(os.path.basename("GroovesharkAPI.py")).hexdigest()
 
        # Constructor
        def __init__(self):
 
        # Constructor
        def __init__(self):
@@ -36,12 +38,12 @@ class GrooveAPI:
                # session ids last 2 weeks
                if self._sessionID == '' or time.time()- self._lastSessionTime >= SESSION_EXPIRY:
                        self._sessionID = self._getSessionID()
                # session ids last 2 weeks
                if self._sessionID == '' or time.time()- self._lastSessionTime >= SESSION_EXPIRY:
                        self._sessionID = self._getSessionID()
-                       self._ip = self._getIP()
-                       self._country = self._getCountry()
                        if self._sessionID == '':
                                raise StandardError('Failed to get session id')
                        else:
                                print "New GrooveAPI session id: " + self._sessionID
                        if self._sessionID == '':
                                raise StandardError('Failed to get session id')
                        else:
                                print "New GrooveAPI session id: " + self._sessionID
+                               self._ip = self._getIP()
+                               self._country = self._getCountry()
                                self._setSavedSession()
 
        # Call to API
                                self._setSavedSession()
 
        # Call to API
@@ -50,6 +52,10 @@ class GrooveAPI:
                        res = self._getRemote(method, params)
                        url = res['url']
                        postData = res['postData']
                        res = self._getRemote(method, params)
                        url = res['url']
                        postData = res['postData']
+               except:
+                       print "Failed to get request URL and post data"
+                       return []
+               try:
                        req = urllib2.Request(url, postData)
                        response = urllib2.urlopen(req)
                        result = response.read()
                        req = urllib2.Request(url, postData)
                        response = urllib2.urlopen(req)
                        result = response.read()
@@ -58,14 +64,25 @@ class GrooveAPI:
                        response.close()
                        result = simplejson.loads(result)
                        return result
                        response.close()
                        result = simplejson.loads(result)
                        return result
+               except urllib2.HTTPError, e:
+                       print "HTTP error " + e.code
+               except urllib2.URLError, e:
+                       print "URL error " + e.reason
                except:
                except:
+                       print "Request to Grooveshark API failed"
                        return []       
 
                        return []       
 
+
        # Get the API call
        def _getRemote(self, method, params = {}):
                postData = { "method": method, "sessionid": self._sessionID, "parameters": params }
                postData = simplejson.dumps(postData)
        # Get the API call
        def _getRemote(self, method, params = {}):
                postData = { "method": method, "sessionid": self._sessionID, "parameters": params }
                postData = simplejson.dumps(postData)
-               url = WEB_APP_URL + "?postData=" + urllib.quote_plus(postData)
+               
+               cipher = Blowfish(self._key)
+               cipher.initCTR()
+               encryptedPostData = cipher.encryptCTR(postData)
+               encryptedPostData = base64.urlsafe_b64encode(encryptedPostData)
+               url = WEB_APP_URL + "?postData=" + encryptedPostData
                req = urllib2.Request(url)
                response = urllib2.urlopen(req)
                result = response.read()
                req = urllib2.Request(url)
                response = urllib2.urlopen(req)
                result = response.read()
@@ -82,8 +99,8 @@ class GrooveAPI:
        def _getSessionID(self):
                params = {}
                result = self._callRemote('startSession', params)
        def _getSessionID(self):
                params = {}
                result = self._callRemote('startSession', params)
-               self._lastSessionTime = time.time()
                if 'result' in result:
                if 'result' in result:
+                       self._lastSessionTime = time.time()
                        return result['result']['sessionID']
                else:
                        return ''
                        return result['result']['sessionID']
                else:
                        return ''
diff --git a/resources/lib/blowfish/__init__.py b/resources/lib/blowfish/__init__.py
new file mode 100644 (file)
index 0000000..0635c58
--- /dev/null
@@ -0,0 +1,692 @@
+#
+# blowfish.py
+# Copyright (C) 2002 Michael Gilfix <mgilfix@eecs.tufts.edu>
+#
+# This module is open source; you can redistribute it and/or
+# modify it under the terms of the GPL or Artistic License.
+# These licenses are available at http://www.opensource.org
+#
+# This software must be used and distributed in accordance
+# with the law. The author claims no liability for its
+# misuse.
+#
+# This program 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.
+#
+
+# This software was modified by Ivan Voras: CTR cipher mode of
+# operation was added, together with testing and example code.
+# These changes are (c) 2007./08. Ivan Voras <ivoras@gmail.com>
+# These changes can be used, modified ad distributed under the
+# GPL or Artistic License, the same as the original module.
+# All disclaimers of warranty from the original module also
+# apply to these changes.
+
+# CBC mode contributed by Joel Edwards <joeledwards@gmail.com>,
+# under the same license conditions.
+
+"""
+Blowfish Encryption
+
+This module is a pure python implementation of Bruce Schneier's
+encryption scheme 'Blowfish'. Blowish is a 16-round Feistel Network
+cipher and offers substantial speed gains over DES.
+
+The key is a string of length anywhere between 64 and 448 bits, or
+equivalently 8 and 56 bytes. The encryption and decryption functions operate
+on 64-bit blocks, or 8 byte strings.
+
+Send questions, comments, bugs my way:
+    Michael Gilfix <mgilfix@eecs.tufts.edu>
+    
+The module has been expanded to include CTR stream encryption/decryption
+mode, built from the primitives from the orignal module. This change
+did not alter any of the base Blowfish code from the original author.
+
+The author of CTR changes is:
+    Ivan Voras <ivoras@gmail.com>
+"""
+
+import struct, types
+
+__author__ = "Michael Gilfix <mgilfix@eecs.tufts.edu>"
+
+class Blowfish:
+
+    """Blowfish encryption Scheme
+
+    This class implements the encryption and decryption
+    functionality of the Blowfish cipher.
+
+    Public functions:
+
+        def __init__ (self, key)
+            Creates an instance of blowfish using 'key'
+            as the encryption key. Key is a string of
+            length ranging from 8 to 56 bytes (64 to 448
+            bits). Once the instance of the object is
+            created, the key is no longer necessary.
+
+        def encrypt (self, data):
+            Encrypt an 8 byte (64-bit) block of text
+            where 'data' is an 8 byte string. Returns an
+            8-byte encrypted string.
+
+        def decrypt (self, data):
+            Decrypt an 8 byte (64-bit) encrypted block
+            of text, where 'data' is the 8 byte encrypted
+            string. Returns an 8-byte string of plaintext.
+
+        def cipher (self, xl, xr, direction):
+            Encrypts a 64-bit block of data where xl is
+            the upper 32-bits and xr is the lower 32-bits.
+            'direction' is the direction to apply the
+            cipher, either ENCRYPT or DECRYPT constants.
+            returns a tuple of either encrypted or decrypted
+            data of the left half and right half of the
+            64-bit block.
+
+        def initCTR(self):
+            Initializes CTR engine for encryption or decryption.
+            
+        def encryptCTR(self, data):
+            Encrypts an arbitrary string and returns the
+            encrypted string. The method can be called successively
+            for multiple string blocks.
+            
+        def decryptCTR(self, data):
+            Decrypts a string encrypted with encryptCTR() and
+            returns the decrypted string.
+            
+    Private members:
+
+        def __round_func (self, xl)
+            Performs an obscuring function on the 32-bit
+            block of data 'xl', which is the left half of
+            the 64-bit block of data. Returns the 32-bit
+            result as a long integer.
+
+    """
+
+    # Cipher directions
+    ENCRYPT = 0
+    DECRYPT = 1
+
+    # For the __round_func
+    modulus = long (2) ** 32
+
+    def __init__ (self, key):
+
+        if not key or len (key) < 8 or len (key) > 56:
+            raise RuntimeError, "Attempted to initialize Blowfish cipher with key of invalid length: %s" % len (key)
+
+        self.p_boxes = [
+            0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
+            0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
+            0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
+            0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917,
+            0x9216D5D9, 0x8979FB1B
+        ]
+
+        self.s_boxes = [
+            [
+                0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7,
+                0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99,
+                0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16,
+                0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E,
+                0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE,
+                0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013,
+                0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF,
+                0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E,
+                0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,
+                0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440,
+                0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE,
+                0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A,
+                0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E,
+                0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677,
+                0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193,
+                0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032,
+                0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88,
+                0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,
+                0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E,
+                0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0,
+                0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3,
+                0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98,
+                0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88,
+                0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE,
+                0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6,
+                0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D,
+                0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,
+                0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7,
+                0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA,
+                0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463,
+                0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F,
+                0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09,
+                0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3,
+                0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB,
+                0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279,
+                0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
+                0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB,
+                0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82,
+                0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB,
+                0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573,
+                0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0,
+                0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B,
+                0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790,
+                0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8,
+                0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,
+                0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0,
+                0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7,
+                0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C,
+                0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD,
+                0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1,
+                0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299,
+                0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9,
+                0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477,
+                0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,
+                0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49,
+                0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF,
+                0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA,
+                0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5,
+                0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41,
+                0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915,
+                0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400,
+                0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915,
+                0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
+                0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A
+            ],
+            [
+                0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623,
+                0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266,
+                0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1,
+                0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E,
+                0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6,
+                0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1,
+                0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E,
+                0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1,
+                0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737,
+                0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8,
+                0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF,
+                0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD,
+                0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701,
+                0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7,
+                0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41,
+                0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331,
+                0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF,
+                0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF,
+                0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E,
+                0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87,
+                0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C,
+                0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2,
+                0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16,
+                0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD,
+                0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B,
+                0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509,
+                0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E,
+                0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3,
+                0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F,
+                0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A,
+                0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4,
+                0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960,
+                0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66,
+                0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28,
+                0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802,
+                0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,
+                0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510,
+                0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF,
+                0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14,
+                0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E,
+                0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50,
+                0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7,
+                0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8,
+                0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281,
+                0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99,
+                0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696,
+                0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128,
+                0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73,
+                0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0,
+                0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0,
+                0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105,
+                0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250,
+                0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3,
+                0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285,
+                0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00,
+                0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
+                0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB,
+                0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E,
+                0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735,
+                0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC,
+                0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9,
+                0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340,
+                0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,
+                0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7
+            ],
+            [
+                0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934,
+                0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068,
+                0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF,
+                0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840,
+                0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45,
+                0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504,
+                0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A,
+                0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB,
+                0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE,
+                0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6,
+                0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42,
+                0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B,
+                0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2,
+                0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB,
+                0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527,
+                0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B,
+                0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33,
+                0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C,
+                0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3,
+                0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC,
+                0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17,
+                0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564,
+                0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B,
+                0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115,
+                0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922,
+                0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728,
+                0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0,
+                0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
+                0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37,
+                0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D,
+                0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804,
+                0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B,
+                0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3,
+                0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB,
+                0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D,
+                0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,
+                0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350,
+                0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9,
+                0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A,
+                0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE,
+                0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D,
+                0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC,
+                0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F,
+                0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61,
+                0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2,
+                0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9,
+                0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2,
+                0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C,
+                0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E,
+                0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633,
+                0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10,
+                0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169,
+                0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52,
+                0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027,
+                0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5,
+                0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62,
+                0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634,
+                0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76,
+                0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24,
+                0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC,
+                0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4,
+                0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C,
+                0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,
+                0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0
+            ],
+            [
+                0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B,
+                0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE,
+                0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B,
+                0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4,
+                0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8,
+                0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6,
+                0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304,
+                0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22,
+                0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,
+                0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6,
+                0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9,
+                0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59,
+                0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593,
+                0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51,
+                0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28,
+                0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C,
+                0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B,
+                0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,
+                0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C,
+                0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD,
+                0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A,
+                0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319,
+                0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB,
+                0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F,
+                0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991,
+                0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32,
+                0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,
+                0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166,
+                0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE,
+                0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB,
+                0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5,
+                0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47,
+                0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370,
+                0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D,
+                0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84,
+                0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
+                0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8,
+                0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD,
+                0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9,
+                0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7,
+                0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38,
+                0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F,
+                0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C,
+                0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525,
+                0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,
+                0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442,
+                0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964,
+                0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
+                0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8,
+                0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D,
+                0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F,
+                0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299,
+                0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02,
+                0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,
+                0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614,
+                0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
+                0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6,
+                0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B,
+                0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0,
+                0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
+                0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E,
+                0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9,
+                0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
+                0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6
+            ]
+        ]
+
+        # Cycle through the p-boxes and round-robin XOR the
+        # key with the p-boxes
+        key_len = len (key)
+        index = 0
+        for i in range (len (self.p_boxes)):
+            val = (ord (key[index % key_len]) << 24) + \
+                  (ord (key[(index + 1) % key_len]) << 16) + \
+                  (ord (key[(index + 2) % key_len]) << 8) + \
+                   ord (key[(index + 3) % key_len])
+            self.p_boxes[i] = self.p_boxes[i] ^ val
+            index = index + 4
+
+        # For the chaining process
+        l, r = 0, 0
+
+        # Begin chain replacing the p-boxes
+        for i in range (0, len (self.p_boxes), 2):
+            l, r = self.cipher (l, r, self.ENCRYPT)
+            self.p_boxes[i] = l
+            self.p_boxes[i + 1] = r
+
+        # Chain replace the s-boxes
+        for i in range (len (self.s_boxes)):
+            for j in range (0, len (self.s_boxes[i]), 2):
+                l, r = self.cipher (l, r, self.ENCRYPT)
+                self.s_boxes[i][j] = l
+                self.s_boxes[i][j + 1] = r
+
+        self.initCTR()
+
+
+    def cipher (self, xl, xr, direction):
+        """Encryption primitive"""
+        if direction == self.ENCRYPT:
+            for i in range (16):
+                xl = xl ^ self.p_boxes[i]
+                xr = self.__round_func (xl) ^ xr
+                xl, xr = xr, xl
+            xl, xr = xr, xl
+            xr = xr ^ self.p_boxes[16]
+            xl = xl ^ self.p_boxes[17]
+        else:
+            for i in range (17, 1, -1):
+                xl = xl ^ self.p_boxes[i]
+                xr = self.__round_func (xl) ^ xr
+                xl, xr = xr, xl
+            xl, xr = xr, xl
+            xr = xr ^ self.p_boxes[1]
+            xl = xl ^ self.p_boxes[0]
+        return xl, xr
+
+
+    def __round_func (self, xl):
+        a = (xl & 0xFF000000) >> 24
+        b = (xl & 0x00FF0000) >> 16
+        c = (xl & 0x0000FF00) >> 8
+        d = xl & 0x000000FF
+
+        # Perform all ops as longs then and out the last 32-bits to
+        # obtain the integer
+        f = (long (self.s_boxes[0][a]) + long (self.s_boxes[1][b])) % self.modulus
+        f = f ^ long (self.s_boxes[2][c])
+        f = f + long (self.s_boxes[3][d])
+        f = (f % self.modulus) & 0xFFFFFFFF
+
+        return f
+
+
+    def encrypt (self, data):
+        if not len (data) == 8:
+            raise RuntimeError, "Attempted to encrypt data of invalid block length: %s" % len(data)
+
+        # Use big endianess since that's what everyone else uses
+        xl = ord (data[3]) | (ord (data[2]) << 8) | (ord (data[1]) << 16) | (ord (data[0]) << 24)
+        xr = ord (data[7]) | (ord (data[6]) << 8) | (ord (data[5]) << 16) | (ord (data[4]) << 24)
+
+        cl, cr = self.cipher (xl, xr, self.ENCRYPT)
+        chars = ''.join ([
+            chr ((cl >> 24) & 0xFF), chr ((cl >> 16) & 0xFF), chr ((cl >> 8) & 0xFF), chr (cl & 0xFF),
+            chr ((cr >> 24) & 0xFF), chr ((cr >> 16) & 0xFF), chr ((cr >> 8) & 0xFF), chr (cr & 0xFF)
+        ])
+        return chars
+
+
+    def decrypt (self, data):
+        if not len (data) == 8:
+            raise RuntimeError, "Attempted to encrypt data of invalid block length: %s" % len(data)
+
+        # Use big endianess since that's what everyone else uses
+        cl = ord (data[3]) | (ord (data[2]) << 8) | (ord (data[1]) << 16) | (ord (data[0]) << 24)
+        cr = ord (data[7]) | (ord (data[6]) << 8) | (ord (data[5]) << 16) | (ord (data[4]) << 24)
+
+        xl, xr = self.cipher (cl, cr, self.DECRYPT)
+        chars = ''.join ([
+            chr ((xl >> 24) & 0xFF), chr ((xl >> 16) & 0xFF), chr ((xl >> 8) & 0xFF), chr (xl & 0xFF),
+            chr ((xr >> 24) & 0xFF), chr ((xr >> 16) & 0xFF), chr ((xr >> 8) & 0xFF), chr (xr & 0xFF)
+        ])
+        return chars
+
+
+    # ==== CBC Mode ====
+    def initCBC(self, iv=0):
+        """Initializes CBC mode of the cypher"""
+        assert struct.calcsize("Q") == self.block_size()
+        self.cbc_iv = struct.pack("Q", iv)
+
+
+    def encryptCBC(self, data):
+        """
+        Encrypts a buffer of data using CBC mode. Multiple successive buffers
+        (belonging to the same logical stream of buffers) can be encrypted
+        with this method one after the other without any intermediate work.
+        Each buffer must be a multiple of 8-octets (64-bits) in length.
+        """
+        if type(data) != types.StringType:
+            raise RuntimeError, "Can only work on 8-bit strings"
+        if (len(data) % 8) != 0:
+            raise RuntimeError, "Can only work with data in 64-bit multiples in CBC mode"
+
+        xor = lambda t: ord(t[0]) ^ ord(t[1])
+        result = ''
+        block_size = self.block_size()
+        for i in range(0, len(data), block_size):
+            p_block = data[i:i+block_size]
+            pair = zip(p_block, self.cbc_iv)
+            j_block = ''.join(map(chr, map(xor, pair)))
+            c_block = self.encrypt(j_block)
+            result += c_block
+            self.cbc_iv = c_block
+        return result
+
+
+    def decryptCBC(self, data):
+        if type(data) != types.StringType:
+            raise RuntimeError, "Can only work on 8-bit strings"
+        if (len(data) % 8) != 0:
+            raise RuntimeError, "Can only work with data in 64-bit multiples in CBC mode"
+
+        xor = lambda t: ord(t[0]) ^ ord(t[1])
+        result = ''
+        block_size = self.block_size()
+        for i in range(0, len(data), block_size):
+            c_block = data[i:i+block_size]
+            j_block = self.decrypt(c_block)
+            pair = zip(j_block, self.cbc_iv)
+            p_block = ''.join(map(chr, map(xor, pair)))
+            result += p_block
+            self.cbc_iv = c_block
+        return result
+
+
+    # ==== CTR Mode ====
+    def initCTR(self, iv=0):
+        """Initializes CTR mode of the cypher"""
+        assert struct.calcsize("Q") == self.block_size()
+        self.ctr_iv = iv
+        self._calcCTRBUF()
+
+
+    def _calcCTRBUF(self):
+        """Calculates one block of CTR keystream"""
+        self.ctr_cks = self.encrypt(struct.pack("Q", self.ctr_iv)) # keystream block
+        self.ctr_iv += 1
+        self.ctr_pos = 0
+
+
+    def _nextCTRByte(self):
+        """Returns one byte of CTR keystream"""
+        b = ord(self.ctr_cks[self.ctr_pos])
+        self.ctr_pos += 1
+        if self.ctr_pos >= len(self.ctr_cks):
+            self._calcCTRBUF()
+        return b
+
+
+    def encryptCTR(self, data):
+        """
+        Encrypts a buffer of data with CTR mode. Multiple successive buffers
+        (belonging to the same logical stream of buffers) can be encrypted
+        with this method one after the other without any intermediate work.
+        """
+        if type(data) != types.StringType:
+            raise RuntimeException, "Can only work on 8-bit strings"
+        result = []
+        for ch in data:
+            result.append(chr(ord(ch) ^ self._nextCTRByte()))
+        return "".join(result)
+
+
+    def decryptCTR(self, data):
+        return self.encryptCTR(data)
+
+
+    def block_size(self):
+        return 8
+
+
+    def key_length(self):
+        return 56
+
+
+    def key_bits(self):
+        return 56 * 8
+
+    @staticmethod
+    def testVectors():
+        import binascii
+        # for more vectors see http://www.schneier.com/code/vectors.txt
+        vectors = (
+            ('0000000000000000',        '0000000000000000',        '4EF997456198DD78'),
+            ('FFFFFFFFFFFFFFFF',        'FFFFFFFFFFFFFFFF',        '51866FD5B85ECB8A'),
+            ('3000000000000000',        '1000000000000001',        '7D856F9A613063F2'),
+            ('1111111111111111',        '1111111111111111',        '2466DD878B963C9D'),
+            ('49E95D6D4CA229BF',        '02FE55778117F12A',        'CF9C5D7A4986ADB5'),
+            ('E0FEE0FEF1FEF1FE',        '0123456789ABCDEF',        'C39E072D9FAC631D'),
+            ('07A7137045DA2A16',        '3BDD119049372802',        '2EEDDA93FFD39C79'),
+        )
+        ok = True
+        for v in vectors:
+            c = Blowfish(binascii.a2b_hex(v[0]))
+            e = binascii.b2a_hex(c.encrypt(binascii.a2b_hex(v[1]))).upper()
+            if e != v[2]:
+                print "VECTOR TEST FAIL: expecting %s, got %s" % (repr(v), e)
+                ok = False
+        return ok
+
+        
+
+##############################################################
+# Module testing
+
+if __name__ == '__main__':
+    if not Blowfish.testVectors():
+        print "WARNING: The implementation doesn't pass algorithm test vectors!"
+    else:
+        print "The implementation passes algorithm test vectors (ECB)."
+
+    key = 'This is a test key'
+    cipher = Blowfish (key)
+
+    print "Testing encryption:"
+    xl = 123456
+    xr = 654321
+    print "\tPlain text: (%s, %s)" %(xl, xr)
+    cl, cr = cipher.cipher (xl, xr, cipher.ENCRYPT)
+    print "\tCrypted is: (%s, %s)" %(cl, cr)
+    dl, dr = cipher.cipher (cl, cr, cipher.DECRYPT)
+    print "\tUnencrypted is: (%s, %s)" %(dl, dr)
+
+    print "Testing block encrypt:"
+    text = 'testtest'
+    print "\tText:\t\t%s" %text
+    crypted = cipher.encrypt(text)
+    print "\tEncrypted:\t%s" % repr(crypted)
+    decrypted = cipher.decrypt(crypted)
+    print "\tDecrypted:\t%s" %decrypted
+    
+    print "Testing CTR encrypt:"
+    cipher.initCTR()
+    text = "The quick brown fox jumps over the lazy dog"
+    print "\tText:\t\t", text
+    crypted = cipher.encryptCTR(text)
+    print "\tEncrypted:\t", repr(crypted)
+    cipher.initCTR()
+    decrypted = cipher.decryptCTR(crypted)
+    print "\tDecrypted:\t", decrypted
+
+    print "Testing CBC encrypt:"
+    cipher.initCBC()
+    text = "Owen's Ornery Old Oryx Obstructed Olga's Optics."
+    print "\tText:\t\t", text
+    crypted = cipher.encryptCBC(text)
+    print "\tEncrypted:\t", repr(crypted)
+    cipher.initCBC()
+    decrypted = cipher.decryptCBC(crypted)
+    print "\tDecrypted:\t", decrypted
+
+    print "Testing speed"
+    from time import time
+    t1 = time()
+    n = 0
+    tlen = 0
+    while True:
+        for i in xrange(1000):
+            tstr = "The quick brown fox jumps over the lazy dog %d" % i
+            enc = cipher.encryptCTR(tstr)
+            tlen += len(tstr)
+        n += 1000
+        t2 = time()
+        if t2 - t1 > 5:
+            break
+    t = t2 - t1
+    print "%d encryptions in %0.1f seconds: %0.1f enc/s, %0.1f bytes/s" % (n, t, n / t, tlen / t)
+
diff --git a/resources/lib/uuid/__init__.py b/resources/lib/uuid/__init__.py
deleted file mode 100644 (file)
index 75d189f..0000000
+++ /dev/null
@@ -1,477 +0,0 @@
-r"""UUID objects (universally unique identifiers) according to RFC 4122.
-
-This module provides immutable UUID objects (class UUID) and the functions
-uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5
-UUIDs as specified in RFC 4122.
-
-If all you want is a unique ID, you should probably call uuid1() or uuid4().
-Note that uuid1() may compromise privacy since it creates a UUID containing
-the computer's network address.  uuid4() creates a random UUID.
-
-Typical usage:
-
-    >>> import uuid
-
-    # make a UUID based on the host ID and current time
-    >>> uuid.uuid1()
-    UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
-
-    # make a UUID using an MD5 hash of a namespace UUID and a name
-    >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
-    UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
-
-    # make a random UUID
-    >>> uuid.uuid4()
-    UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
-
-    # make a UUID using a SHA-1 hash of a namespace UUID and a name
-    >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
-    UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
-
-    # make a UUID from a string of hex digits (braces and hyphens ignored)
-    >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
-
-    # convert a UUID to a string of hex digits in standard form
-    >>> str(x)
-    '00010203-0405-0607-0809-0a0b0c0d0e0f'
-
-    # get the raw 16 bytes of the UUID
-    >>> x.bytes
-    '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
-
-    # make a UUID from a 16-byte string
-    >>> uuid.UUID(bytes=x.bytes)
-    UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
-
-This module works with Python 2.3 or higher."""
-
-__author__ = 'Ka-Ping Yee <ping@zesty.ca>'
-__date__ = '$Date: 2006/06/12 23:15:40 $'.split()[1].replace('/', '-')
-__version__ = '$Revision: 1.30 $'.split()[1]
-
-RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
-    'reserved for NCS compatibility', 'specified in RFC 4122',
-    'reserved for Microsoft compatibility', 'reserved for future definition']
-
-class UUID(object):
-    """Instances of the UUID class represent UUIDs as specified in RFC 4122.
-    UUID objects are immutable, hashable, and usable as dictionary keys.
-    Converting a UUID to a string with str() yields something in the form
-    '12345678-1234-1234-1234-123456789abc'.  The UUID constructor accepts
-    four possible forms: a similar string of hexadecimal digits, or a
-    string of 16 raw bytes as an argument named 'bytes', or a tuple of
-    six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and
-    48-bit values respectively) as an argument named 'fields', or a single
-    128-bit integer as an argument named 'int'.
-    
-    UUIDs have these read-only attributes:
-
-        bytes       the UUID as a 16-byte string
-
-        fields      a tuple of the six integer fields of the UUID,
-                    which are also available as six individual attributes
-                    and two derived attributes:
-
-            time_low                the first 32 bits of the UUID
-            time_mid                the next 16 bits of the UUID
-            time_hi_version         the next 16 bits of the UUID
-            clock_seq_hi_variant    the next 8 bits of the UUID
-            clock_seq_low           the next 8 bits of the UUID
-            node                    the last 48 bits of the UUID
-
-            time                    the 60-bit timestamp
-            clock_seq               the 14-bit sequence number
-
-        hex         the UUID as a 32-character hexadecimal string
-
-        int         the UUID as a 128-bit integer
-
-        urn         the UUID as a URN as specified in RFC 4122
-
-        variant     the UUID variant (one of the constants RESERVED_NCS,
-                    RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)
-
-        version     the UUID version number (1 through 5, meaningful only
-                    when the variant is RFC_4122)
-    """
-
-    def __init__(self, hex=None, bytes=None, fields=None, int=None,
-                       version=None):
-        r"""Create a UUID from either a string of 32 hexadecimal digits,
-        a string of 16 bytes as the 'bytes' argument, a tuple of six
-        integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
-        8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
-        the 'fields' argument, or a single 128-bit integer as the 'int'
-        argument.  When a string of hex digits is given, curly braces,
-        hyphens, and a URN prefix are all optional.  For example, these
-        expressions all yield the same UUID:
-
-        UUID('{12345678-1234-5678-1234-567812345678}')
-        UUID('12345678123456781234567812345678')
-        UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
-        UUID(bytes='\x12\x34\x56\x78'*4)
-        UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
-        UUID(int=0x12345678123456781234567812345678)
-
-        Exactly one of 'hex', 'bytes', 'fields', or 'int' must be given.
-        The 'version' argument is optional; if given, the resulting UUID
-        will have its variant and version number set according to RFC 4122,
-        overriding bits in the given 'hex', 'bytes', 'fields', or 'int'.
-        """
-
-        if [hex, bytes, fields, int].count(None) != 3:
-            raise TypeError('need just one of hex, bytes, fields, or int')
-        if hex is not None:
-            hex = hex.replace('urn:', '').replace('uuid:', '')
-            hex = hex.strip('{}').replace('-', '')
-            if len(hex) != 32:
-                raise ValueError('badly formed hexadecimal UUID string')
-            int = long(hex, 16)
-        if bytes is not None:
-            if len(bytes) != 16:
-                raise ValueError('bytes is not a 16-char string')
-            int = long(('%02x'*16) % tuple(map(ord, bytes)), 16)
-        if fields is not None:
-            if len(fields) != 6:
-                raise ValueError('fields is not a 6-tuple')
-            (time_low, time_mid, time_hi_version,
-             clock_seq_hi_variant, clock_seq_low, node) = fields
-            if not 0 <= time_low < 1<<32L:
-                raise ValueError('field 1 out of range (need a 32-bit value)')
-            if not 0 <= time_mid < 1<<16L:
-                raise ValueError('field 2 out of range (need a 16-bit value)')
-            if not 0 <= time_hi_version < 1<<16L:
-                raise ValueError('field 3 out of range (need a 16-bit value)')
-            if not 0 <= clock_seq_hi_variant < 1<<8L:
-                raise ValueError('field 4 out of range (need an 8-bit value)')
-            if not 0 <= clock_seq_low < 1<<8L:
-                raise ValueError('field 5 out of range (need an 8-bit value)')
-            if not 0 <= node < 1<<48L:
-                raise ValueError('field 6 out of range (need a 48-bit value)')
-            clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low
-            int = ((time_low << 96L) | (time_mid << 80L) |
-                   (time_hi_version << 64L) | (clock_seq << 48L) | node)
-        if int is not None:
-            if not 0 <= int < 1<<128L:
-                raise ValueError('int is out of range (need a 128-bit value)')
-        if version is not None:
-            if not 1 <= version <= 5:
-                raise ValueError('illegal version number')
-            # Set the variant to RFC 4122.
-            int &= ~(0xc000 << 48L)
-            int |= 0x8000 << 48L
-            # Set the version number.
-            int &= ~(0xf000 << 64L)
-            int |= version << 76L
-        self.__dict__['int'] = int
-
-    def __cmp__(self, other):
-        if isinstance(other, UUID):
-            return cmp(self.int, other.int)
-        return NotImplemented
-
-    def __hash__(self):
-        return hash(self.int)
-
-    def __int__(self):
-        return self.int
-
-    def __repr__(self):
-        return 'UUID(%r)' % str(self)
-
-    def __setattr__(self, name, value):
-        raise TypeError('UUID objects are immutable')
-
-    def __str__(self):
-        hex = '%032x' % self.int
-        return '%s-%s-%s-%s-%s' % (
-            hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
-
-    def get_bytes(self):
-        bytes = ''
-        for shift in range(0, 128, 8):
-            bytes = chr((self.int >> shift) & 0xff) + bytes
-        return bytes
-
-    bytes = property(get_bytes)
-
-    def get_fields(self):
-        return (self.time_low, self.time_mid, self.time_hi_version,
-                self.clock_seq_hi_variant, self.clock_seq_low, self.node)
-
-    fields = property(get_fields)
-
-    def get_time_low(self):
-        return self.int >> 96L
-   
-    time_low = property(get_time_low)
-
-    def get_time_mid(self):
-        return (self.int >> 80L) & 0xffff
-
-    time_mid = property(get_time_mid)
-
-    def get_time_hi_version(self):
-        return (self.int >> 64L) & 0xffff
-    
-    time_hi_version = property(get_time_hi_version)
-
-    def get_clock_seq_hi_variant(self):
-        return (self.int >> 56L) & 0xff
-
-    clock_seq_hi_variant = property(get_clock_seq_hi_variant)
-    
-    def get_clock_seq_low(self):
-        return (self.int >> 48L) & 0xff
-
-    clock_seq_low = property(get_clock_seq_low)
-
-    def get_time(self):
-        return (((self.time_hi_version & 0x0fffL) << 48L) |
-                (self.time_mid << 32L) | self.time_low)
-
-    time = property(get_time)
-
-    def get_clock_seq(self):
-        return (((self.clock_seq_hi_variant & 0x3fL) << 8L) |
-                self.clock_seq_low)
-
-    clock_seq = property(get_clock_seq)
-    
-    def get_node(self):
-        return self.int & 0xffffffffffff
-
-    node = property(get_node)
-
-    def get_hex(self):
-        return '%032x' % self.int
-
-    hex = property(get_hex)
-
-    def get_urn(self):
-        return 'urn:uuid:' + str(self)
-
-    urn = property(get_urn)
-
-    def get_variant(self):
-        if not self.int & (0x8000 << 48L):
-            return RESERVED_NCS
-        elif not self.int & (0x4000 << 48L):
-            return RFC_4122
-        elif not self.int & (0x2000 << 48L):
-            return RESERVED_MICROSOFT
-        else:
-            return RESERVED_FUTURE
-
-    variant = property(get_variant)
-
-    def get_version(self):
-        # The version bits are only meaningful for RFC 4122 UUIDs.
-        if self.variant == RFC_4122:
-            return int((self.int >> 76L) & 0xf)
-
-    version = property(get_version)
-
-def _ifconfig_getnode():
-    """Get the hardware address on Unix by running ifconfig."""
-    import os
-    for dir in ['', '/sbin/', '/usr/sbin']:
-        try:
-            pipe = os.popen(os.path.join(dir, 'ifconfig'))
-        except IOError:
-            continue
-        for line in pipe:
-            words = line.lower().split()
-            for i in range(len(words)):
-                if words[i] in ['hwaddr', 'ether']:
-                    return int(words[i + 1].replace(':', ''), 16)
-
-def _ipconfig_getnode():
-    """Get the hardware address on Windows by running ipconfig.exe."""
-    import os, re
-    dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
-    try:
-        import ctypes
-        buffer = ctypes.create_string_buffer(300)
-        ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300)
-        dirs.insert(0, buffer.value.decode('mbcs'))
-    except:
-        pass
-    for dir in dirs:
-        try:
-            pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
-        except IOError:
-            continue
-        for line in pipe:
-            value = line.split(':')[-1].strip().lower()
-            if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
-                return int(value.replace('-', ''), 16)
-
-def _netbios_getnode():
-    """Get the hardware address on Windows using NetBIOS calls.
-    See http://support.microsoft.com/kb/118623 for details."""
-    import win32wnet, netbios
-    ncb = netbios.NCB()
-    ncb.Command = netbios.NCBENUM
-    ncb.Buffer = adapters = netbios.LANA_ENUM()
-    adapters._pack()
-    if win32wnet.Netbios(ncb) != 0:
-        return
-    adapters._unpack()
-    for i in range(adapters.length):
-        ncb.Reset()
-        ncb.Command = netbios.NCBRESET
-        ncb.Lana_num = ord(adapters.lana[i])
-        if win32wnet.Netbios(ncb) != 0:
-            continue
-        ncb.Reset()
-        ncb.Command = netbios.NCBASTAT
-        ncb.Lana_num = ord(adapters.lana[i])
-        ncb.Callname = '*'.ljust(16)
-        ncb.Buffer = status = netbios.ADAPTER_STATUS()
-        if win32wnet.Netbios(ncb) != 0:
-            continue
-        status._unpack()
-        bytes = map(ord, status.adapter_address)
-        return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
-                (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
-
-# Thanks to Thomas Heller for ctypes and for his help with its use here.
-
-# If ctypes is available, use it to find system routines for UUID generation.
-_uuid_generate_random = _uuid_generate_time = _UuidCreate = None
-try:
-    import ctypes, ctypes.util
-    _buffer = ctypes.create_string_buffer(16)
-
-    # The uuid_generate_* routines are provided by libuuid on at least
-    # Linux and FreeBSD, and provided by libc on Mac OS X.
-    for libname in ['uuid', 'c']:
-        try:
-            lib = ctypes.CDLL(ctypes.util.find_library(libname))
-        except:
-            continue
-        if hasattr(lib, 'uuid_generate_random'):
-            _uuid_generate_random = lib.uuid_generate_random
-        if hasattr(lib, 'uuid_generate_time'):
-            _uuid_generate_time = lib.uuid_generate_time
-
-    # On Windows prior to 2000, UuidCreate gives a UUID containing the
-    # hardware address.  On Windows 2000 and later, UuidCreate makes a
-    # random UUID and UuidCreateSequential gives a UUID containing the
-    # hardware address.  These routines are provided by the RPC runtime.
-    try:
-        lib = ctypes.windll.rpcrt4
-    except:
-        lib = None
-    _UuidCreate = getattr(lib, 'UuidCreateSequential',
-                          getattr(lib, 'UuidCreate', None))
-except:
-    pass
-
-def _unixdll_getnode():
-    """Get the hardware address on Unix using ctypes."""
-    _uuid_generate_time(_buffer)
-    return UUID(bytes=_buffer.raw).node
-
-def _windll_getnode():
-    """Get the hardware address on Windows using ctypes."""
-    if _UuidCreate(_buffer) == 0:
-        return UUID(bytes=_buffer.raw).node
-
-def _random_getnode():
-    """Get a random node ID, with eighth bit set as suggested by RFC 4122."""
-    import random
-    return random.randrange(0, 1<<48L) | 0x010000000000L
-
-_node = None
-
-def getnode():
-    """Get the hardware address as a 48-bit integer.  The first time this
-    runs, it may launch a separate program, which could be quite slow.  If
-    all attempts to obtain the hardware address fail, we choose a random
-    48-bit number with its eighth bit set to 1 as recommended in RFC 4122."""
-
-    global _node
-    if _node is not None:
-        return _node
-
-    import sys
-    if sys.platform == 'win32':
-        getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
-    else:
-        getters = [_unixdll_getnode, _ifconfig_getnode]
-
-    for getter in getters + [_random_getnode]:
-        try:
-            _node = getter()
-        except:
-            continue
-        if _node is not None:
-            return _node
-
-def uuid1(node=None, clock_seq=None):
-    """Generate a UUID from a host ID, sequence number, and the current time.
-    If 'node' is not given, getnode() is used to obtain the hardware
-    address.  If 'clock_seq' is given, it is used as the sequence number;
-    otherwise a random 14-bit sequence number is chosen."""
-
-    # When the system provides a version-1 UUID generator, use it (but don't
-    # use UuidCreate here because its UUIDs don't conform to RFC 4122).
-    if _uuid_generate_time and node is clock_seq is None:
-        _uuid_generate_time(_buffer)
-        return UUID(bytes=_buffer.raw)
-
-    import time
-    nanoseconds = int(time.time() * 1e9)
-    # 0x01b21dd213814000 is the number of 100-ns intervals between the
-    # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
-    timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
-    if clock_seq is None:
-        import random
-        clock_seq = random.randrange(1<<14L) # instead of stable storage
-    time_low = timestamp & 0xffffffffL
-    time_mid = (timestamp >> 32L) & 0xffffL
-    time_hi_version = (timestamp >> 48L) & 0x0fffL
-    clock_seq_low = clock_seq & 0xffL
-    clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
-    if node is None:
-        node = getnode()
-    return UUID(fields=(time_low, time_mid, time_hi_version,
-                        clock_seq_hi_variant, clock_seq_low, node), version=1)
-
-def uuid3(namespace, name):
-    """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
-    import md5
-    hash = md5.md5(namespace.bytes + name).digest()
-    return UUID(bytes=hash[:16], version=3)
-
-def uuid4():
-    """Generate a random UUID."""
-
-    # When the system provides a version-4 UUID generator, use it.
-    if _uuid_generate_random:
-        _uuid_generate_random(_buffer)
-        return UUID(bytes=_buffer.raw)
-
-    # Otherwise, get randomness from urandom or the 'random' module.
-    try:
-        import os
-        return UUID(bytes=os.urandom(16), version=4)
-    except:
-        import random
-        bytes = [chr(random.randrange(256)) for i in range(16)]
-        return UUID(bytes=bytes, version=4)
-
-def uuid5(namespace, name):
-    """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
-    import sha
-    hash = sha.sha(namespace.bytes + name).digest()
-    return UUID(bytes=hash[:16], version=5)
-
-# The following standard UUIDs are for use with uuid3() or uuid5().
-
-NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
-NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
-NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
-NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')