-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathPyImgEnc.py
95 lines (77 loc) · 3.73 KB
/
PyImgEnc.py
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
import sys
import cv2
import numpy as np
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
# This program encrypts a jpg With AES-256. The encrypted image contains more data than the original image (e.g. because of
# padding, IV etc.). Therefore the encrypted image has one row more. Supported are CBC and ECB mode.
# Set mode
mode = AES.MODE_CBC
#mode = AES.MODE_ECB
if mode != AES.MODE_CBC and mode != AES.MODE_ECB:
print('Only CBC and ECB mode supported...')
sys.exit()
# Set sizes
keySize = 32
ivSize = AES.block_size if mode == AES.MODE_CBC else 0
#
# Start Encryption ----------------------------------------------------------------------------------------------
#
# Load original image
imageOrig = cv2.imread("topsecret.jpg")
rowOrig, columnOrig, depthOrig = imageOrig.shape
# Check for minimum width
minWidth = (AES.block_size + AES.block_size) // depthOrig + 1
if columnOrig < minWidth:
print('The minimum width of the image must be {} pixels, so that IV and padding can be stored in a single additional row!'.format(minWidth))
sys.exit()
# Display original image
cv2.imshow("Original image", imageOrig)
cv2.waitKey()
# Convert original image data to bytes
imageOrigBytes = imageOrig.tobytes()
# Encrypt
key = get_random_bytes(keySize)
iv = get_random_bytes(ivSize)
cipher = AES.new(key, AES.MODE_CBC, iv) if mode == AES.MODE_CBC else AES.new(key, AES.MODE_ECB)
imageOrigBytesPadded = pad(imageOrigBytes, AES.block_size)
ciphertext = cipher.encrypt(imageOrigBytesPadded)
# Convert ciphertext bytes to encrypted image data
# The additional row contains columnOrig * DepthOrig bytes. Of this, ivSize + paddedSize bytes are used
# and void = columnOrig * DepthOrig - ivSize - paddedSize bytes unused
paddedSize = len(imageOrigBytesPadded) - len(imageOrigBytes)
void = columnOrig * depthOrig - ivSize - paddedSize
ivCiphertextVoid = iv + ciphertext + bytes(void)
imageEncrypted = np.frombuffer(ivCiphertextVoid, dtype = imageOrig.dtype).reshape(rowOrig + 1, columnOrig, depthOrig)
# Display encrypted image
cv2.imshow("Encrypted image", imageEncrypted)
cv2.waitKey()
# Save the encrypted image (optional)
# If the encrypted image is to be stored, a format must be chosen that does not change the data. Otherwise,
# decryption is not possible after loading the encrypted image. bmp does not change the data, but jpg does.
# When saving with imwrite, the format is controlled by the extension (.jpg, .bmp). The following works:
# cv2.imwrite("topsecretEnc.bmp", imageEncrypted)
# imageEncrypted = cv2.imread("topsecretEnc.bmp")
#
# Start Decryption ----------------------------------------------------------------------------------------------
#
# Convert encrypted image data to ciphertext bytes
rowEncrypted, columnOrig, depthOrig = imageEncrypted.shape
rowOrig = rowEncrypted - 1
encryptedBytes = imageEncrypted.tobytes()
iv = encryptedBytes[:ivSize]
imageOrigBytesSize = rowOrig * columnOrig * depthOrig
paddedSize = (imageOrigBytesSize // AES.block_size + 1) * AES.block_size - imageOrigBytesSize
encrypted = encryptedBytes[ivSize : ivSize + imageOrigBytesSize + paddedSize]
# Decrypt
cipher = AES.new(key, AES.MODE_CBC, iv) if mode == AES.MODE_CBC else AES.new(key, AES.MODE_ECB)
decryptedImageBytesPadded = cipher.decrypt(encrypted)
decryptedImageBytes = unpad(decryptedImageBytesPadded, AES.block_size)
# Convert bytes to decrypted image data
decryptedImage = np.frombuffer(decryptedImageBytes, imageEncrypted.dtype).reshape(rowOrig, columnOrig, depthOrig)
# Display decrypted image
cv2.imshow("Decrypted Image", decryptedImage)
cv2.waitKey()
# Close all windows
cv2.destroyAllWindows()