Universal College of Engineering, Kaman
Department of Computer Engineering
Subject:CSS
Experiment no: 6
Roll No: 55 Name: Krutika Pandya Div: B Batch: B1
AIM: To implement SHA Algorithm
PROGRAM:
import struct
class SHA1:
"""
A pure Python implementation of the SHA-1 hash function.
This implementation is for educational purposes only and should
not be used for production environments due to its potential
performance limitations and lack of optimizations.
"""
def __init__(self):
# Initial hash values
self.h = [
0x67452301,
0xEFCDAB89,
0x98BADCFE,
0x10325476,
0xC3D2E1F0,
]
# Message block buffer
[Link] = bytearray()
# Length of the original message (in bits)
self.message_len = 0
def _preprocess(self, message):
"""
Preprocesses the message by padding it according to the SHA-1
standard.
"""
# Convert message to bytearray if it's not already
if isinstance(message, str):
message = [Link]('utf-8')
elif isinstance(message, bytes):
message = bytearray(message)
[Link] = message
self.message_len = len(message) * 8 # Length in bits
# Append "1" bit (followed by 0s)
[Link](0x80) # 0x80 is 10000000 in binary
# Pad with zeros until length is congruent to 448 mod 512
while (len([Link]) * 8) % 512 != 448:
[Link](0x00)
# Append length (in bits) as a 64-bit big-endian integer
[Link] += [Link]('>Q', self.message_len) # >Q for big-endian unsigned long long
return [Link]
def _process_block(self, block):
"""
Processes a single 512-bit (64-byte) block of the message.
"""
# Initialize message schedule (W)
w = [0] * 80
# Break block into 16 big-endian words
for i in range(16):
w[i] = [Link]('>I', block[i * 4:i * 4 + 4])[0] # >I for big-endian unsigned int
# Extend the first 16 words into the remaining 64 words
for i in range(16, 80):
w[i] = self._leftrotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1)
# Initialize working variables to current hash value
a, b, c, d, e = self.h
# SHA-1 main loop (80 rounds)
for i in range(80):
if 0 <= i <= 19:
f = (b & c) | ((~b) & d)
k = 0x5A827999
elif 20 <= i <= 39:
f=b^c^d
k = 0x6ED9EBA1
elif 40 <= i <= 59:
f = (b & c) | (b & d) | (c & d)
k = 0x8F1BBCDC
elif 60 <= i <= 79:
f=b^c^d
k = 0xCA62C1D6
temp = (self._leftrotate(a, 5) + f + e + k + w[i]) & 0xFFFFFFFF # Ensure 32-bit result
e=d
d=c
c = self._leftrotate(b, 30)
b=a
a = temp
# Add the compressed chunk to current hash value
self.h[0] = (self.h[0] + a) & 0xFFFFFFFF
self.h[1] = (self.h[1] + b) & 0xFFFFFFFF
self.h[2] = (self.h[2] + c) & 0xFFFFFFFF
self.h[3] = (self.h[3] + d) & 0xFFFFFFFF
self.h[4] = (self.h[4] + e) & 0xFFFFFFFF
def _leftrotate(self, value, bits):
"""
Performs a left bitwise rotation of a 32-bit value.
"""
value &= 0xFFFFFFFF # Ensure value is 32-bit
return ((value << bits) | (value >> (32 - bits))) & 0xFFFFFFFF # Ensure result is 32-bit
def update(self, message):
"""
Updates the hash with a new chunk of data. This function *can* be
called multiple times to hash data incrementally.
"""
if isinstance(message, str):
message = [Link]('utf-8') # Encode to bytes
[Link] += bytearray(message)
self.message_len += len(message) * 8 # Update the length in bits
def digest(self):
"""
Calculates the final SHA-1 hash value.
"""
# Preprocess the complete message (including any data from `update` calls)
padded_message = self._preprocess(bytes([Link]))
# Process message in 512-bit (64-byte) chunks
for i in range(0, len(padded_message), 64):
block = padded_message[i:i + 64]
self._process_block(block)
# Return the hash as a byte string
return b''.join([Link]('>I', h) for h in self.h)
def hexdigest(self):
"""
Returns the SHA-1 hash value as a hexadecimal string.
"""
return ''.join('%08x' % h for h in self.h)
def hash(self, message):
"""
Hashes the given message in a single call. This is a convenience
function for simple use cases.
"""
self.__init__() # reset the state for reuse
[Link](message)
return [Link]()
# Example usage:
if __name__ == "__main__":
message = "UNIVERSAL ENGINEERING COLLEGE"
sha1 = SHA1()
# Example 1: Hashing in a single call
hash_value = [Link](message)
print(f"SHA-1 hash of '{message}': {hash_value}")
# Example 2: Incremental hashing
sha1 = SHA1() # Create a new SHA1 object
[Link]("Hello")
[Link](", ")
[Link]("world!")
hash_value = [Link]()
print(f"SHA-1 hash of '{message}' (incremental): {hash_value}")
# Example of hashing an empty string
sha1 = SHA1()
empty_hash = [Link]("")
print(f"SHA-1 hash of an empty string: {empty_hash}")
# Testing with a larger message
long_message = "This is a much longer message to demonstrate how the SHA-1 algorithm
handles different message lengths. It should be long enough to trigger the padding process."
sha1 = SHA1()
long_hash = [Link](long_message)
print(f"SHA-1 hash of a longer message: {long_hash}")
OUTPUT: