blob: a91d0fe92f779836c535ddfb6c9be2bee339dbad [file] [log] [blame]
Teng Liang12286002015-06-10 12:52:22 -07001# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2#
3# Copyright (C) 2014 Regents of the University of California.
Teng Liang29aa6012015-06-28 15:31:01 -07004# Author: Teng Liang <philoliang2011@gmail.com>
Teng Liang12286002015-06-10 12:52:22 -07005#
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.
19from pyndn.encoding import WireFormat
20from pyndn.util import Blob
21from pyndn.digest_sha256_signature import DigestSha256Signature
22from pyndn import Data, KeyLocatorType, Interest, Name
23from hashlib import sha256
24from random import SystemRandom
25from time import time as timestamp
26
27import hmac
28
29class 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