Teng Liang | 1228600 | 2015-06-10 12:52:22 -0700 | [diff] [blame] | 1 | # -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */ |
| 2 | # |
| 3 | # Copyright (C) 2014 Regents of the University of California. |
Teng Liang | 29aa601 | 2015-06-28 15:31:01 -0700 | [diff] [blame] | 4 | # Author: Teng Liang <philoliang2011@gmail.com> |
Teng Liang | 1228600 | 2015-06-10 12:52:22 -0700 | [diff] [blame] | 5 | # |
| 6 | # This program is free software: you can redistribute it and/or modify |
| 7 | # it under the terms of the GNU Lesser General Public License as published by |
| 8 | # the Free Software Foundation, either version 3 of the License, or |
| 9 | # (at your option) any later version. |
| 10 | # |
| 11 | # This program is distributed in the hope that it will be useful, |
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | # GNU General Public License for more details. |
| 15 | # |
| 16 | # You should have received a copy of the GNU General Public License |
| 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 18 | # A copy of the GNU General Public License is in the file COPYING. |
| 19 | from pyndn.encoding import WireFormat |
| 20 | from pyndn.util import Blob |
| 21 | from pyndn.digest_sha256_signature import DigestSha256Signature |
| 22 | from pyndn import Data, KeyLocatorType, Interest, Name |
| 23 | from hashlib import sha256 |
| 24 | from random import SystemRandom |
| 25 | from time import time as timestamp |
| 26 | |
| 27 | import hmac |
| 28 | |
| 29 | class HmacHelper(object): |
| 30 | def __init__(self, raw_key, wireFormat=None): |
| 31 | super(HmacHelper, self).__init__() |
| 32 | self.key = sha256(raw_key).digest() |
| 33 | self.random = SystemRandom() |
| 34 | if wireFormat is None: |
| 35 | self.wireFormat = WireFormat.getDefaultWireFormat() |
| 36 | else: |
| 37 | self.wireFormat = wireFormat |
| 38 | |
| 39 | @classmethod |
| 40 | def generatePin(cls): |
| 41 | """ |
| 42 | Generate a pin to be entered into another device. |
| 43 | Restricting this to 8 bytes (16 hex chars) for now. |
| 44 | """ |
| 45 | pin = bytearray(8) |
| 46 | random = SystemRandom() |
| 47 | for i in range(8): |
| 48 | pin[i] = random.randint(0,0xff) |
| 49 | return str(pin).encode('hex') |
| 50 | |
| 51 | @classmethod |
| 52 | def extractInterestSignature(cls, interest, wireFormat=None): |
| 53 | if wireFormat is None: |
| 54 | wireFormat = WireFormat.getDefaultWireFormat() |
| 55 | |
| 56 | try: |
| 57 | signature = wireFormat.decodeSignatureInfoAndValue( |
| 58 | interest.getName().get(-2).getValue().buf(), |
| 59 | interest.getName().get(-1).getValue().buf()) |
| 60 | except: |
| 61 | signature = None |
| 62 | |
| 63 | return signature |
| 64 | |
| 65 | def signData(self, data, keyName=None, wireFormat=None): |
| 66 | data.setSignature(DigestSha256Signature()) |
| 67 | s = data.getSignature() |
| 68 | |
| 69 | #s.getKeyLocator().setType(KeyLocatorType.KEYNAME) |
| 70 | #s.getKeyLocator().setKeyName(keyName) |
| 71 | |
| 72 | if wireFormat is None: |
| 73 | wireFormat = WireFormat.getDefaultWireFormat() |
| 74 | encoded = data.wireEncode(wireFormat) |
| 75 | signer = hmac.new(self.key, bytearray(encoded.toSignedBuffer()), sha256) |
| 76 | s.setSignature(Blob(signer.digest())) |
| 77 | data.wireEncode(wireFormat) |
| 78 | |
| 79 | def verifyData(self, data, wireFormat=None): |
| 80 | # clear out old signature so encoding does not include it |
| 81 | if wireFormat is None: |
| 82 | wireFormat = WireFormat.getDefaultWireFormat() |
| 83 | encoded = data.wireEncode(wireFormat) |
| 84 | hasher = hmac.new(self.key, bytearray(encoded.toSignedBuffer()), sha256) |
| 85 | sigBytes = data.getSignature().getSignature() |
| 86 | return sigBytes.toRawStr() == hasher.digest() |
| 87 | |
| 88 | def signInterest(self, interest, keyName=None, wireFormat=None): |
| 89 | # Adds the nonce and timestamp here, because there is no |
| 90 | # 'makeCommandInterest' call for this yet |
| 91 | nonceValue = bytearray(8) |
| 92 | for i in range(8): |
| 93 | nonceValue[i] = self.random.randint(0,0xff) |
| 94 | timestampValue = bytearray(8) |
| 95 | ts = int(timestamp()*1000) |
| 96 | for i in range(8): |
| 97 | byte = ts & 0xff |
| 98 | timestampValue[-(i+1)] = byte |
| 99 | ts = ts >> 8 |
| 100 | |
| 101 | if wireFormat is None: |
| 102 | wireFormat = WireFormat.getDefaultWireFormat() |
| 103 | |
| 104 | s = DigestSha256Signature() |
| 105 | #s.getKeyLocator().setType(KeyLocatorType.KEYNAME) |
| 106 | #s.getKeyLocator().setKeyName(keyName) |
| 107 | |
| 108 | interestName = interest.getName() |
| 109 | interestName.append(nonceValue).append(timestampValue) |
| 110 | interestName.append(wireFormat.encodeSignatureInfo(s)) |
| 111 | interestName.append(Name.Component()) |
| 112 | |
| 113 | encoding = interest.wireEncode(wireFormat) |
| 114 | signer = hmac.new(self.key, encoding.toSignedBuffer(), sha256) |
| 115 | |
| 116 | s.setSignature(Blob(signer.digest())) |
| 117 | interest.setName(interestName.getPrefix(-1).append( |
| 118 | wireFormat.encodeSignatureValue(s))) |
| 119 | |
| 120 | |
| 121 | def verifyInterest(self, interest, wireFormat=None): |
| 122 | if wireFormat is None: |
| 123 | wireFormat = WireFormat.getDefaultWireFormat() |
| 124 | |
| 125 | signature = self.extractInterestSignature(interest, wireFormat) |
| 126 | encoding = interest.wireEncode(wireFormat) |
| 127 | hasher = hmac.new(self.key, encoding.toSignedBuffer(), sha256) |
| 128 | return signature.getSignature().toRawStr() == hasher.digest() |
| 129 | |