PageRenderTime 55ms CodeModel.GetById 17ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 0ms

/gdata/tlslite/utils/Python_RSAKey.py

http://radioappz.googlecode.com/
Python | 209 lines | 183 code | 16 blank | 10 comment | 8 complexity | d0eaa4836f51d58f1deb5cf6376a8f00 MD5 | raw file
  1"""Pure-Python RSA implementation."""
  2
  3from cryptomath import *
  4import xmltools
  5from ASN1Parser import ASN1Parser
  6from RSAKey import *
  7
  8class Python_RSAKey(RSAKey):
  9    def __init__(self, n=0, e=0, d=0, p=0, q=0, dP=0, dQ=0, qInv=0):
 10        if (n and not e) or (e and not n):
 11            raise AssertionError()
 12        self.n = n
 13        self.e = e
 14        self.d = d
 15        self.p = p
 16        self.q = q
 17        self.dP = dP
 18        self.dQ = dQ
 19        self.qInv = qInv
 20        self.blinder = 0
 21        self.unblinder = 0
 22
 23    def hasPrivateKey(self):
 24        return self.d != 0
 25
 26    def hash(self):
 27        s = self.writeXMLPublicKey('\t\t')
 28        return hashAndBase64(s.strip())
 29
 30    def _rawPrivateKeyOp(self, m):
 31        #Create blinding values, on the first pass:
 32        if not self.blinder:
 33            self.unblinder = getRandomNumber(2, self.n)
 34            self.blinder = powMod(invMod(self.unblinder, self.n), self.e,
 35                                  self.n)
 36
 37        #Blind the input
 38        m = (m * self.blinder) % self.n
 39
 40        #Perform the RSA operation
 41        c = self._rawPrivateKeyOpHelper(m)
 42
 43        #Unblind the output
 44        c = (c * self.unblinder) % self.n
 45
 46        #Update blinding values
 47        self.blinder = (self.blinder * self.blinder) % self.n
 48        self.unblinder = (self.unblinder * self.unblinder) % self.n
 49
 50        #Return the output
 51        return c
 52
 53
 54    def _rawPrivateKeyOpHelper(self, m):
 55        #Non-CRT version
 56        #c = powMod(m, self.d, self.n)
 57
 58        #CRT version  (~3x faster)
 59        s1 = powMod(m, self.dP, self.p)
 60        s2 = powMod(m, self.dQ, self.q)
 61        h = ((s1 - s2) * self.qInv) % self.p
 62        c = s2 + self.q * h
 63        return c
 64
 65    def _rawPublicKeyOp(self, c):
 66        m = powMod(c, self.e, self.n)
 67        return m
 68
 69    def acceptsPassword(self): return False
 70
 71    def write(self, indent=''):
 72        if self.d:
 73            s = indent+'<privateKey xmlns="http://trevp.net/rsa">\n'
 74        else:
 75            s = indent+'<publicKey xmlns="http://trevp.net/rsa">\n'
 76        s += indent+'\t<n>%s</n>\n' % numberToBase64(self.n)
 77        s += indent+'\t<e>%s</e>\n' % numberToBase64(self.e)
 78        if self.d:
 79            s += indent+'\t<d>%s</d>\n' % numberToBase64(self.d)
 80            s += indent+'\t<p>%s</p>\n' % numberToBase64(self.p)
 81            s += indent+'\t<q>%s</q>\n' % numberToBase64(self.q)
 82            s += indent+'\t<dP>%s</dP>\n' % numberToBase64(self.dP)
 83            s += indent+'\t<dQ>%s</dQ>\n' % numberToBase64(self.dQ)
 84            s += indent+'\t<qInv>%s</qInv>\n' % numberToBase64(self.qInv)
 85            s += indent+'</privateKey>'
 86        else:
 87            s += indent+'</publicKey>'
 88        #Only add \n if part of a larger structure
 89        if indent != '':
 90            s += '\n'
 91        return s
 92
 93    def writeXMLPublicKey(self, indent=''):
 94        return Python_RSAKey(self.n, self.e).write(indent)
 95
 96    def generate(bits):
 97        key = Python_RSAKey()
 98        p = getRandomPrime(bits/2, False)
 99        q = getRandomPrime(bits/2, False)
100        t = lcm(p-1, q-1)
101        key.n = p * q
102        key.e = 3L  #Needed to be long, for Java
103        key.d = invMod(key.e, t)
104        key.p = p
105        key.q = q
106        key.dP = key.d % (p-1)
107        key.dQ = key.d % (q-1)
108        key.qInv = invMod(q, p)
109        return key
110    generate = staticmethod(generate)
111
112    def parsePEM(s, passwordCallback=None):
113        """Parse a string containing a <privateKey> or <publicKey>, or
114        PEM-encoded key."""
115
116        start = s.find("-----BEGIN PRIVATE KEY-----")
117        if start != -1:
118            end = s.find("-----END PRIVATE KEY-----")
119            if end == -1:
120                raise SyntaxError("Missing PEM Postfix")
121            s = s[start+len("-----BEGIN PRIVATE KEY -----") : end]
122            bytes = base64ToBytes(s)
123            return Python_RSAKey._parsePKCS8(bytes)
124        else:
125            start = s.find("-----BEGIN RSA PRIVATE KEY-----")
126            if start != -1:
127                end = s.find("-----END RSA PRIVATE KEY-----")
128                if end == -1:
129                    raise SyntaxError("Missing PEM Postfix")
130                s = s[start+len("-----BEGIN RSA PRIVATE KEY -----") : end]
131                bytes = base64ToBytes(s)
132                return Python_RSAKey._parseSSLeay(bytes)
133        raise SyntaxError("Missing PEM Prefix")
134    parsePEM = staticmethod(parsePEM)
135
136    def parseXML(s):
137        element = xmltools.parseAndStripWhitespace(s)
138        return Python_RSAKey._parseXML(element)
139    parseXML = staticmethod(parseXML)
140
141    def _parsePKCS8(bytes):
142        p = ASN1Parser(bytes)
143
144        version = p.getChild(0).value[0]
145        if version != 0:
146            raise SyntaxError("Unrecognized PKCS8 version")
147
148        rsaOID = p.getChild(1).value
149        if list(rsaOID) != [6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0]:
150            raise SyntaxError("Unrecognized AlgorithmIdentifier")
151
152        #Get the privateKey
153        privateKeyP = p.getChild(2)
154
155        #Adjust for OCTET STRING encapsulation
156        privateKeyP = ASN1Parser(privateKeyP.value)
157
158        return Python_RSAKey._parseASN1PrivateKey(privateKeyP)
159    _parsePKCS8 = staticmethod(_parsePKCS8)
160
161    def _parseSSLeay(bytes):
162        privateKeyP = ASN1Parser(bytes)
163        return Python_RSAKey._parseASN1PrivateKey(privateKeyP)
164    _parseSSLeay = staticmethod(_parseSSLeay)
165
166    def _parseASN1PrivateKey(privateKeyP):
167        version = privateKeyP.getChild(0).value[0]
168        if version != 0:
169            raise SyntaxError("Unrecognized RSAPrivateKey version")
170        n = bytesToNumber(privateKeyP.getChild(1).value)
171        e = bytesToNumber(privateKeyP.getChild(2).value)
172        d = bytesToNumber(privateKeyP.getChild(3).value)
173        p = bytesToNumber(privateKeyP.getChild(4).value)
174        q = bytesToNumber(privateKeyP.getChild(5).value)
175        dP = bytesToNumber(privateKeyP.getChild(6).value)
176        dQ = bytesToNumber(privateKeyP.getChild(7).value)
177        qInv = bytesToNumber(privateKeyP.getChild(8).value)
178        return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv)
179    _parseASN1PrivateKey = staticmethod(_parseASN1PrivateKey)
180
181    def _parseXML(element):
182        try:
183            xmltools.checkName(element, "privateKey")
184        except SyntaxError:
185            xmltools.checkName(element, "publicKey")
186
187        #Parse attributes
188        xmltools.getReqAttribute(element, "xmlns", "http://trevp.net/rsa\Z")
189        xmltools.checkNoMoreAttributes(element)
190
191        #Parse public values (<n> and <e>)
192        n = base64ToNumber(xmltools.getText(xmltools.getChild(element, 0, "n"), xmltools.base64RegEx))
193        e = base64ToNumber(xmltools.getText(xmltools.getChild(element, 1, "e"), xmltools.base64RegEx))
194        d = 0
195        p = 0
196        q = 0
197        dP = 0
198        dQ = 0
199        qInv = 0
200        #Parse private values, if present
201        if element.childNodes.length>=3:
202            d = base64ToNumber(xmltools.getText(xmltools.getChild(element, 2, "d"), xmltools.base64RegEx))
203            p = base64ToNumber(xmltools.getText(xmltools.getChild(element, 3, "p"), xmltools.base64RegEx))
204            q = base64ToNumber(xmltools.getText(xmltools.getChild(element, 4, "q"), xmltools.base64RegEx))
205            dP = base64ToNumber(xmltools.getText(xmltools.getChild(element, 5, "dP"), xmltools.base64RegEx))
206            dQ = base64ToNumber(xmltools.getText(xmltools.getChild(element, 6, "dQ"), xmltools.base64RegEx))
207            qInv = base64ToNumber(xmltools.getText(xmltools.getLastChild(element, 7, "qInv"), xmltools.base64RegEx))
208        return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv)
209    _parseXML = staticmethod(_parseXML)