File: tools.py

package info (click to toggle)
tboot 1.10.5-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 6,000 kB
  • sloc: ansic: 56,029; python: 6,595; perl: 2,303; sh: 455; asm: 442; makefile: 377
file content (183 lines) | stat: -rw-r--r-- 7,470 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#!/usr/bin/python
#  Copyright (c) 2013, Intel Corporation. All rights reserved.

#  TXT Policy Generator Tool - tools invoked from tools menu
#     Hash image
#     Insert policy into image

# using print() built infunction, disable print statement
from __future__ import print_function

try:
  import wx
except ImportWxError:
  raise ImportWxError, "Please download the appropriate version of wxPython from www.wxpython.org"

try:
  import os
except ImportOsError:
  raise ImportOsError, "import OS failed"

import array
import M2Crypto
import struct

# Pycrypto module from: https://www.dlitz.net/software/pycrypto/ is required
#try:
#  from Crypto.Hash import SHA               # SHA1
#  from Crypto.Hash import SHA256            # SHA256
#except ImportError:
#  raise ImportError, "PyCrypto import failed. Please install PyCrypto ..."

from defines import DEFINES
from util import UTILS
utilities = UTILS()


class TOOLS(object):

  # hash a bios image 'file' [i.e. base.bin] from 'startOffset' for 'offsetSize' bytes,
  # and write the hash to base.hash, as a LCP2 raw hash file, and base.dat as an 'ascii coded binary'
  # I.e. if the image's hash starts with:  0xB0, 0x61, 0x52, ...
  # then  the    .hash file  starts with:  B0 61 52 ...   (i.e. the raw binary hash)
  # and   the    .dat  file  starts with:  42 30 20 36 31 20 35 32 20
  # (i.e. each hex digit is represented by its ascii equivalent with an ascii space after each hex pair

  # Parameters
  #   biosFileName - name of the bios file to be hashed
  #   startOffset  - offset into the file to start hashing from, aka base
  #   offsetSize   - size to hash from startOffset
  #   hashAlg      - hash algorithm to use, TPM_ALG_XXXX where XXXX is SHA1 or SHA256

  # Return True on success or
  #        False on any error
  #
  def hashImage(self, biosFileName, startOffsetStr, offsetSizeStr, hashAlgStr):
    """hashImage - generate the hash of the specified file from start address for size bytes"""
    function = 'hashImage'

    biosPath = os.path.abspath(os.path.normpath(biosFileName))
    startOffset = int(startOffsetStr, 16)
    offsetSize  = int(offsetSizeStr, 16)
    hashAlg     = int(hashAlgStr, 16)

    MAX_BIOS_SIZE = 0x1000000;
    print("%s - biosFile=%s, startOffset=0x%x, offsetSize=0x%x, hashAlg=%d" %
          (function, biosPath, startOffset, offsetSize, hashAlg))  # DBGDBG

    # use biosFile's base name for the .tmp and .hash files
    #   biosFile - file to be hashed, ie if biosFileName = biosXYZ.bin then base = biosXYZ
    #   tempFile - base.tmp - temp file containing the data to hash
    #     i.e. biosFile's data from startOffset to startOffset+offsetSize
    #   hashFile - base.hash - output file containg the hash of tempFile

    # verify that biosFile can be opened
    try:
      biosFile = open(biosPath, 'rb')
    except:
      print("Unable to open specified file: %s" % (biosPath))
      return False

    # strip off the .ext leaving the base
    if(biosFileName.endswith('.bin') == True):
      base = os.path.basename(biosFileName).split('.bin')
    else:
      print("Expected .bin extention for Bios File %s" % (biosPath))
      return False

    #TODO:  will all bios files have .bin extentions??????????????????????????????????????
    #print("%s - base=%s" % (function, base[0]))  # DBGDBG

    # verify that .tmp, .dat and .hash files can be created in the current dir, else exit
    tmpFileName  = utilities.formFileName(base[0], "tmp")
    hashFileName = utilities.formFileName(base[0], "hash")
    datFileName  = utilities.formFileName(base[0], "dat")
    #print("%s - tmpFileName=%s, hashFileName=%s" % (function, tmpFileName, hashFileName)) # DBGDBG
    try:
      tmpFile = open(tmpFileName, 'wb')
    except:
      print("Unable to create file: %s" % (tmpFileName))
      biosFile.close()
      return False

    try:
      hashFile = open(hashFileName, 'wb')
    except:
      print("Unable to create file: %s" % (hashFileName))
      tmpFile.close()
      biosFile.close()
      return False

    try:
      datFile = open(datFileName, 'wb')
    except:
      print("Unable to create file: %s" % (datFileName))
      tmpFile.close()
      biosFile.close()
      datFile.close()
      return False

    # Determine biosFile's size
    biosFile.seek (0, os.SEEK_END)
    biosFileSize = biosFile.tell()

    # if startOffset > MAX_BIOS_SIZE, then adjust startOffset to be relative to 4Gb
    if (startOffset > MAX_BIOS_SIZE):
      print("The specified StartOffset(0x%x) is > than the max bios size(%x) Assuming StartOffset is relative to 4Gb" %
        (startOffset, MAX_BIOS_SIZE))
      beginingOfBiosImage = 0x100000000 - biosFileSize;
      startOffset = startOffset - beginingOfBiosImage;
      print("%s - startOffset now 0x%x, MAX_BIOS_SIZE=0x%x" % (startOffset, MAX_BIOS_SIZE))

    # If startOffset + offsetSize > biosFile's size, adjust offsetSize
    if(startOffset + offsetSize > biosFileSize):
      print("%s - The specified StartOffset(0x%x) + offsetSize(0x%x) is larger than biosFileSize(0x%x)" %
        (function, startOffset, offsetSize, biosFileSize))
      offsetSize = biosFileSize - startOffset;
      print("StartOffset+OffsetSize > BiosFileSize. Resetting OffsetSize to 0x%x" % (offsetSize))

    #print("%s - biosFileSize=0x%x, startOffset+offsetSize=0x%x, MAX_BIOS_SIZE=0x%x" % (function, biosFileSize, startOffset+offsetSize, MAX_BIOS_SIZE)) # DBGDBG
    # buffer the part of the bios that will be hashed in base.tmp
    #   open the bios file,
    #   set the read pointer to: startOffset
    #   read offsetSize bytes into tempFile
    data = array.array ("B")
    biosFile.seek(startOffset, os.SEEK_SET)
    #print("%s - pos=0x%x" % (function, biosFile.tell())) # DBGDBG
    data.fromfile(biosFile, offsetSize)

    # Initialize to None to check for supported HashAlg.
    hashAlgName = None
    # reverse lookup of the hash algorithm name(key) for the given HashAlg value
    hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == hashAlg)).next()

    if (hashAlgName != None):
      # This handles all SHA hash algorithms.
      hash = M2Crypto.EVP.MessageDigest(hashAlgName.lower())
    else:
      self.StatusBar.SetStatusText("Hash Algorithm %d is not supported" % (hashAlg))
      return False

    hash.update(data)
    hashdigest = hash.digest()  # cannot call this M2Crypto function twice.

    print(data, end='', file=tmpFile )        # for testing that the right data was hashed
    print(hashdigest, end='', file=hashFile )
    hexHash = hashdigest.encode('hex')
    print("Image's hash: %s" % (hexHash))
    print("Generated hash files: %s.hash and %s.dat" % (base[0],base[0]))

    # generate the .dat from hexHash: convert each hex byte to a ascii digit followed by a space
    i=0
    while(i < len(hexHash)):
      print(hexHash[i].upper(),   end='', file=datFile )    # 1st hexdigit as upper case ascii
      print(hexHash[i+1].upper(), end='', file=datFile )    # 2nd hexdigit as upper case ascii
      print(' ',          end='', file=datFile )            # space after each pair
      i += 2
    print('\n', end='', file=datFile )                      # final LF to match WinLCP

    biosFile.close()
    tmpFile.close()
    hashFile.close()
    datFile.close()
    return True