/gdata/tlslite/utils/Python_RSAKey.py

http://radioappz.googlecode.com/ · Python · 209 lines · 159 code · 32 blank · 18 comment · 21 complexity · d0eaa4836f51d58f1deb5cf6376a8f00 MD5 · raw file

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