├── README.md
└── src
├── DRMLSB.py
├── newPepper.png
└── pepper.png
/README.md:
--------------------------------------------------------------------------------
1 |
2 | Digital rights management based on blockchain and steganography
3 |
4 | Introduction:
5 |
6 |
7 | Every day, more and more information is shared via the internet. As a result, developing robust, secure systems to protect this data is critical. We frequently employ blockchain for digital rights management considering how powerful this technologie is in sharing data securely. The following steps have been implemented in our proposed system: Digital watermarking using Least Significant Bit algorithm (LSB) -we will be trying to use (DWT) later on- , SHA-256 hashing function, watermark extraction and a mini Blockchain creation.
8 |
9 |
10 |
11 |
12 | * ### Digital rights management :
13 | Digital rights management (DRM) is a method of protecting digital media copyrights. This strategy entails the use of technologies that restrict the copying and use of copyrighted works as well as proprietary software. Digital rights management, in some ways, allows publishers or authors to control what paying users can do with their works. Implementing [digital rights management solutions](https://www.vera.com/why-vera/) or processes for businesses can help prevent users from accessing or using specific assets, allowing the organization to avoid legal issues that arise from unauthorized use.
14 | * ### Blockchain technology :
15 |
16 | A blockchain is a sophisticated record of transactions.The name derives from its structure, in which individual records, known as blocks, are linked together in a single list known as a chain.Blockchain is a distributed and decentralized computerized record that records exchanges over a global network of PCs where the data is extremely verified .Blockchain applications include healthcare, voting, food and supply, real estate, and agriculture.
17 |
18 | The blockchain has grown in popularity for the following reasons:
19 |
20 | * it is decentralized because it is not owned by a single person.
21 | The data is cryptographically stored within.
22 | * It is transparent, which means that the user's personal information is kept secure,but all transactions can be viewed as open-source.
23 | * It is immutable, so no one can tinker with the data that is inside the blockchain.
24 | * Accuracy of the chain is attained.
25 | * Blockchain eliminates the need for third-party verification and cost.
26 |
27 |
28 |
29 | 
30 |
31 |
32 | _For further details you can check this article [Implementing a blockchain](https://jis-eurasipjournals.springeropen.com/counter/pdf/10.1186/s13635-019-0085-3.pdf) ._
33 |
34 |
35 | * ### Digital Watermarking :
36 | The process of digital watermarking is to insert certain data (image, text, logo) known as watermark inside the host digital data (audio, image, video) without severely affecting the visible quality of host data. The watermark may be in the form of- binary logo, a randomly generated sequence, digital signature, some biometric traits. The main perseverance of digital watermarking is to offer copyright authentication and copyright protection. he applications where copyright protection is required robust watermarking needs to be done.
37 |
38 |
39 | # Summary:
40 | - [***Proposed system:***]()
41 | - [***Digital watermarking:***]()
42 | - [***LSB*** steganography]()
43 | - [***DWT*** steganography]()
44 | - [***Blockchain:***]()
45 | - [Getting started!]()
46 | - [The *hashing* method]()
47 | - [Defining the *Blockchain* class]()
48 | - [Mining *Blocks*]()
49 | - [***Making our First transaction:***]()
50 |
51 |
52 |
53 |
54 | I.     Proposed system :
55 |
56 |
57 | The proposed system was implemented in two stages:
58 | 1. Watermark process
59 | 2. Blockchain Process.
60 |
61 | >*this figure illustrates the proposed system of watermarking and blockchain process.*
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | First, the owner of the item being sold must embed **(LSB/DWT steg)** his/her fingerprint or signature ***in our case the signature will be the full name of the owner hashed using SHA-256***. Each transaction must have 3 parameters : *A buyer - A seller - an item (image in our case)*. In the transaction process we will decode the image, get the signature, compare it the legit signature of the owner and finally validate the transaction change the ownership of the image by and add the new block to the chain.
70 |
71 |
72 | II.     Digital watermarking :
73 |
74 | Least significant bit (LSB) :
75 |
76 | Least significant bit (LSB) insertion is a common and straightforward method of embedding information in a cover image.For example, one simple scheme proposed is to embed the data in the least significant bit (LSB) of each pixel in the cover image.The altered image is known as a stego-image.Although changing the LSB has no effect on image quality for human perception, this scheme is vulnerable to a variety of image processing attacks such as compression, cropping, and so on.
77 |
78 | >we will be working with this algorithm! ***(for now)***
79 |
80 | Discret wavelet transform (DWT) :
81 |
82 | We select an image using the DWT technique.This image is divided into blocks of 8 bit x 8 bit size.Now we take the first block and decompose it using DWT up to the third level.We embed the first part of the secret message in the LH3 region.The secret message that must be embedded in the given image (size less than 400 characters) and converted into an ASCII value and then to a bit stream, where every 8 bits represents a character.The inverse of this technique is used to extract a hidden message from a stego-image.
83 | > I m still working on this .
84 |
85 | III.     Blockchain :
86 |
87 | Once data is committed to the chain, the blockchain is designed to hold immutable information, therefore it is a decentralized, distributed, and immutable database in which data is logically structured as a sequence of smaller chunks (blocks). A cryptographic hash function `H(Bi1)` connects each block `Bi`>0 immutably to a single preceding block `Bi-1`. Changes to `Bi-1` would result in an invalid hash in Bi and all subsequent blocks. The very first block, `B0` is known as the genesis block because it is the only one without a predecessor. A block is typically digitally signed to ensure the integrity of the block and the data contained within it.
88 |
89 | ## *Getting started!*
90 | To store data in each block, we'll use the standard JSON format. The data for each block will be similar to this:
91 | ``` json
92 | {"ID": 1, "images": "newPepper.png",
93 | "timestamp": 1667923557.3992326,
94 | "previousHash": "653c992479d5635e83d8d191e991a03b9e77647760765bbfbf0a",
95 | "nonce": 148872,
96 | "hash": "000041be88bc970ec985b59f6d5b9527175c35b47523329b043bcer34z"}
97 | ```
98 | To implement this we should first make a block class with the given attributes. In order to prevent redundancies, we also want to make each block distinct (by adding giving each block a distinct ID ):
99 |
100 | ```python
101 | class Block:
102 | def __init__(self, ID, image, timestamp, previousHash):
103 | self.ID = ID
104 | self.image = image
105 | self.timestamp = timestamp
106 | self.previousHash = previousHash
107 | self.nonce = 0
108 | ```
109 | `Image`: *the image to be sold/bought*
110 |
111 | `timestamp`: *The timestamp is a small data stored in each block as a unique serial and whose main function is to determine the exact moment in which the block has been mined and validated by the network*
112 |
113 | `previousHash`: *the hash of the previous block*
114 |
115 |
116 | >we'll discuss the nonce later on !
117 |
118 | ## The *hashing* method:
119 | We will convert as mentioned earlier our objects **(block)** into a ***JSON*** string format (*this process is called serialization*), and then we will hash the output with ***SHA-256***.
120 | ```python
121 | def compute_hash(self):
122 | data = json.dumps(self.__dict__, sort_keys=True)
123 | return sha256(data.encode()).hexdigest()
124 | ```
125 | ## Defining the *Blockchain* class:
126 |
127 | A blockchain as we mentioned earlier is a chain of blocks, I like to give the example of the *Linked List* considering how similar they are.
128 |
129 | The blockchain will have 6 main methods:
130 | * ```create_firstBlock()```: Creates the genesis block.
131 | * ```LastBlock()```: returns the last block.
132 | * ```addBlock()```: Creates a new block and adds it to the chain.
133 | * ```add_new_transaction()```: performs a transaction -*we will discuss this later*-
134 | * ```POW()```: the proof of work method -***this needs explanation***-
135 |
136 | The ***proof-of-work*** system makes performing the labor required to create a new block progressively more difficult. This means that anyone who edits a prior block must redo the work of the block and all subsequent blocks. the proof-of-work mechanism keeps on changing the ***nonce*** (*attribute of block object*) and then hashing the block's data until it finds a hash that starts with a certain number of zeros . The ***difficulty*** is defined as the number of leading zero bits. Because the average labor required to generate a block grows exponentially with the number of leading zero bits, we can sufficiently restrict users from altering prior blocks by raising the complexity with each new block.
137 | * ```mineBlock()```: We will discuss this in next!
138 |
139 | ```python
140 | class Blockchain:
141 | difficulty = 4
142 | """""
143 | we will be implementing an algorithm with a dynamic difficulty later on!
144 | """""
145 | def __init__(self):
146 | self.chain = []
147 | self.create_firstBlock()
148 |
149 | def create_firstBlock(self):
150 | firstBlock = Block(0, [], time.time(), "0")
151 | firstBlock.hash = firstBlock.compute_hash()
152 | self.chain.append(firstBlock)
153 |
154 | @property
155 | def lastBlock(self):
156 | return self.chain[-1]
157 | def add_block(self, block, proof):
158 | previous = self.lastBlock.hash
159 | if previous != block.previousHash:
160 | return False
161 | if not self.is_valid(block, proof):
162 | return False
163 |
164 | block.hash = proof
165 | self.chain.append(block)
166 | return True
167 | def pOw(self, block):
168 |
169 | block.nonce = 0
170 |
171 | computedHash = block.compute_hash()
172 | while not computedHash.startswith('0' * Blockchain.difficulty):
173 | block.nonce += 1
174 | computedHash = block.compute_hash()
175 |
176 | return computedHash
177 |
178 | def add_new_transaction(self, image,seller,buyer):
179 | self.unconfirmedImages = image
180 | self.seller = seller
181 | self.buyer = buyer
182 |
183 | ```
184 | ## Mining blocks:
185 | First we should verify the transaction, change ownership of the item and then confirme the transaction create a new block via the block class constructor and check the POW and then add the block to the tail of the chain , this whole process (Combination of all the other methods) is called mining.
186 |
187 | ```python
188 | def mineBlock(self):
189 | imageS = Image.open(self.unconfirmedImages)
190 | fingerPrint = LSB().decode_image(imageS)
191 | if not self.unconfirmedImages:
192 | return False
193 | if fingerPrint != self.seller.fingerprint:
194 | print("false")
195 | return False
196 | imageB = LSB().encode_image(image2, self.buyer.fingerprint)
197 | imageB.save("newPepper.png")
198 | lastBlock = self.lastBlock
199 |
200 | newBlock = Block(ID=lastBlock.ID + 1,
201 | images=self.unconfirmedImages,
202 | timestamp=time.time(),
203 | previousHash=lastBlock.hash)
204 | proof = self.pOw(newBlock)
205 | self.add_block(newBlock, proof)
206 |
207 | self.unconfirmedImages = []
208 | return newBlock.ID
209 | ```
210 | IX.     Test :
211 |
212 | ### Making our First transaction:
213 | as we mentioned in the proposed system we must create a class user/node referring to the buyer/seller and then test our system by adding a transaction then mining a block.
214 | ```python
215 | blockchain = Blockchain()
216 | seller1 = User("Alice","ALice17")
217 | buyer1 = User("Bob","Bob25")
218 | image = Image.open("pepper.png")
219 | image1 = LSB().encode_image(image,seller1.fingerprint)
220 | image1.save("newPepper.png")
221 | blockchain.add_new_transaction("newPepper.png",seller1,buyer1)
222 | blockchain.mineBlock()
223 | ```
224 | we'll create a simple app with flask in which we will visualise our chain.
225 | ```python
226 | app = Flask(__name__)
227 | @app.route('/chain', methods=['GET'])
228 | def get_chain():
229 | chain_data = []
230 | for block in blockchain.chain:
231 | chain_data.append(block.__dict__)
232 | return json.dumps({"length": len(chain_data),
233 | "chain": chain_data})
234 |
235 | app.run(debug=True, port=3000)
236 | ```
237 | if you run the code you'll see something similar to this:
238 |
239 | 
240 |
241 | now we simply run this command in terminal ```curl http://127.0.0.1:3000/chain```
242 |
243 | ***Result***:
244 |
245 | 
246 |
247 | Thank you!!
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
--------------------------------------------------------------------------------
/src/DRMLSB.py:
--------------------------------------------------------------------------------
1 |
2 | from hashlib import sha256
3 | import json
4 | import time
5 | from PIL import Image
6 | from flask import Flask
7 |
8 | class LSB():
9 | def encode_image(self,img, msg):
10 | length = len(msg)
11 | if length > 255:
12 | print("text too long! (don't exeed 255 characters)")
13 | return False
14 | encoded = img.copy()
15 | width, height = img.size
16 | index = 0
17 | for row in range(height):
18 | for col in range(width):
19 | if img.mode != 'RGB':
20 | r, g, b ,a = img.getpixel((col, row))
21 | elif img.mode == 'RGB':
22 | r, g, b = img.getpixel((col, row))
23 | # first value is length of msg
24 | if row == 0 and col == 0 and index < length:
25 | asc = length
26 | elif index <= length:
27 | c = msg[index -1]
28 | asc = ord(c)
29 | else:
30 | asc = b
31 | encoded.putpixel((col, row), (r, g , asc))
32 | index += 1
33 | return encoded
34 |
35 | def decode_image(self,img):
36 | width, height = img.size
37 | msg = ""
38 | index = 0
39 | for row in range(height):
40 | for col in range(width):
41 | if img.mode != 'RGB':
42 | r, g, b ,a = img.getpixel((col, row))
43 | elif img.mode == 'RGB':
44 | r, g, b = img.getpixel((col, row))
45 | if row == 0 and col == 0:
46 | length = b
47 | elif index <= length:
48 | msg += chr(b)
49 | index += 1
50 | return msg
51 |
52 | class Block:
53 | def __init__(self, ID, images, timestamp, previousHash):
54 | self.ID = ID
55 | self.images = images
56 | self.timestamp = timestamp
57 | self.previousHash = previousHash
58 | self.nonce = 0
59 |
60 | def compute_hash(self):
61 | data = json.dumps(self.__dict__, sort_keys=True)
62 | return sha256(data.encode()).hexdigest()
63 |
64 |
65 | class Blockchain:
66 | difficulty = 4
67 | """""
68 | we will be implementing an algorithm with a dynamic difficulty later on!
69 | """""
70 |
71 | def __init__(self):
72 | self.chain = []
73 | self.create_firstBlock()
74 |
75 | def create_firstBlock(self):
76 | firstBlock = Block(0, [], time.time(), "0")
77 | firstBlock.hash = firstBlock.compute_hash()
78 | self.chain.append(firstBlock)
79 |
80 | @property
81 | def lastBlock(self):
82 | return self.chain[-1]
83 |
84 | def add_block(self, block, proof):
85 |
86 | previous = self.lastBlock.hash
87 |
88 | if previous != block.previousHash:
89 | return False
90 |
91 | if not self.is_valid(block, proof):
92 | return False
93 |
94 | block.hash = proof
95 | self.chain.append(block)
96 | return True
97 |
98 | def is_valid(self, block, hashN):
99 |
100 | return (hashN.startswith('0' * Blockchain.difficulty) and
101 | hashN == block.compute_hash())
102 |
103 | def pOw(self, block):
104 |
105 | block.nonce = 0
106 |
107 | computedHash = block.compute_hash()
108 | while not computedHash.startswith('0' * Blockchain.difficulty):
109 | block.nonce += 1
110 | computedHash = block.compute_hash()
111 |
112 | return computedHash
113 |
114 | def add_new_transaction(self, image,seller,buyer):
115 | self.unconfirmedImages = image
116 | self.seller = seller
117 | self.buyer = buyer
118 |
119 | def mineBlock(self):
120 | imageS = Image.open(self.unconfirmedImages)
121 | fingerPrint = LSB().decode_image(imageS)
122 | if not self.unconfirmedImages:
123 | return False
124 | if fingerPrint != self.seller.fingerprint:
125 | print("false")
126 | return False
127 | imageB = LSB().encode_image(image2, self.buyer.fingerprint)
128 | imageB.save("newPepper.png")
129 | lastBlock = self.lastBlock
130 |
131 | newBlock = Block(ID=lastBlock.ID + 1,
132 | images=self.unconfirmedImages,
133 | timestamp=time.time(),
134 | previousHash=lastBlock.hash)
135 | proof = self.pOw(newBlock)
136 | self.add_block(newBlock, proof)
137 |
138 | self.unconfirmedImages = []
139 | return newBlock.ID
140 |
141 | class User:
142 | def __init__(self,name,fingerprint):
143 | self.name = name
144 | self.fingerprint = sha256(fingerprint.encode()).hexdigest()
145 |
146 |
147 | blockchain = Blockchain()
148 | seller1 = User("Alice","ALice17")
149 | buyer1 = User("Bob","Bob25")
150 | image2 = Image.open("pepper.png")
151 | image1 = LSB().encode_image(image2,seller1.fingerprint)
152 | image1.save("newPepper.png")
153 | blockchain.add_new_transaction("newPepper.png",seller1,buyer1)
154 | blockchain.mineBlock()
155 |
156 |
157 |
158 |
159 |
160 | app = Flask(__name__)
161 | @app.route('/chain', methods=['GET'])
162 | def get_chain():
163 | chain_data = []
164 | for block in blockchain.chain:
165 | chain_data.append(block.__dict__)
166 | return json.dumps({"length": len(chain_data),
167 | "chain": chain_data})
168 |
169 | app.run(debug=True, port=3000)
170 |
171 |
172 |
--------------------------------------------------------------------------------
/src/newPepper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mohammedAcheddad/DRM-using-Watermarking-and-blockchain/0427c90d1d8ec309dc03bd5d4723951f4d122338/src/newPepper.png
--------------------------------------------------------------------------------
/src/pepper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mohammedAcheddad/DRM-using-Watermarking-and-blockchain/0427c90d1d8ec309dc03bd5d4723951f4d122338/src/pepper.png
--------------------------------------------------------------------------------