Taking a look at encrypting passwords in Genpass
Feb 18, 2025

Recently, I have been working on some additional functionality to add to genpass to encrypt the output of genpass for future implementations of password storage. Today, I am going to be talking about the current status of where the project stands, and future projections of where I want this project to go.
Currently, I am working out a way to store passwords into pictures using steganography, and in this post I hope to further elaborate on why I chose this method of password storage over traditional methods. More to come.
Why and what is Steganography?
Steganography is the art and method of obscuring and hiding information in plain sight. Think of it as that one scene in the DaVinci code where Tom Hanks and Audrey Tautou used a UV light to discover the next clue on the wall displaying the Mona Lisa. Steganography had always been a popular tool to hide and pass information without raising any alarm bells for anyone searching for information.
Steganography makes a good tool to obscure and store passwords, because if an attacker infiltrates your system; and you had a place where obvious information is stored like a text file containing your passwords— that would be very damning. So, in regards to trying mitigate this threat for my users, I believe that implementing steganography will greatly thwart this threat.
The reason I argue this is because:
Unless they hold the original hash, and original file for an image, an image with modified bytes is unnoticeable.
With proper encryption, and the use of least significant bit steganography, a password is undetectable inside of an encrypted block within an image.
When critical information is stored within an image, there is a large knowledge curve on how to extract the bytes of an image, and with encryption applied to the byte stream for the password, it is increasingly difficult and costly to crack.
Block Ciphers, AES-128, and Steganography
So the first choice I had to make was with what encryption algorithm I wanted to choose for encrypting my passwords, and which one best suits my needs overall. For the crate I happily chose WiseAIDev's Stegano Crate as this crate serves both as a way to both encrypt and store information within JPEGs and PNGs. I have also looked at other crates related to steganography, but I have only had time to really test this crate and so far, it's pretty damn good for what I need it to do.
The first testing phase was the ability for encryption. So far I had to account for two limitations:
Encryption requires the payload to be formatted into a way such that the length of the inputted byte vector is divisible by 16.
The key for the encryption/decryption process must be no longer than 16 bytes.
I'll talk about my proposed solutions for the second limitation, but first let me talk about how I solved the first one.
Formatting the payload so that payload.len()%16=0
The crate itself contains a method that pads the vector with zeroes, but I found out quickly that this only works when the string vector is less than 16. So to solve this I had to create my own solution:
We can see the result of this function working here:
Here, we can see that the byte vector of the original payload was 27, but when we ran the encryption function, an additional 5 bytes were pushed to make the vector 32— a number divisible by 16.
Because the vector was encrypted, they are non-zero values, however when we run the decryption process those bytes are dropped by the OS because they are NULL values. Of course, they aren't dropped out of existence— but they are ignored visually.
Key must be no longer than 16 bytes.
At the current moment, I am still figuring out how I want to tackle this issue. I have considered the following, with the current ranking of my desire to implement (last is least desirable):
Run the encryption function x amount of times using every 16 characters of an inputted key as the next iteration's key.
Create a hash or base64 string based on the inputted key, truncate it to 16 bytes.
Truncate the original key to 16 bytes, which happens by default, and accept the 16-length key limitation.
So far, implementing the first option has been a pain, and I have yet to get it to work properly. Once I do, I will update this article on how I got it to work as well as uploading the code to explain the thought process behind it. In the meantime, lets look at our other options, and why I would rather work on the first one.
Create a hash/base64 string from an inputted key.
This is a security risk, a huge security risk. This is because the first 16 characters of a hash or encoded base64 string are super easy to recreate with numerous methods that allow an attacker to decrypt the key without knowing the original. The only security measure that prevents this is the fact that the file may be overlooked by an attacker.
The only reason I considered this option was because I can obtain the first 16 characters easily, what I might consider however is to take 16 random characters, and then store the position of each character into a seperately encrypted bytestream, and encode that into the destination image.
Truncating the key.
This already happens by default and leaves the user to fend for themselves by creating a password of length 16 to encrypt their own payload. Could be useful, could be a curse.
Overall Progress and conclusions:
Honestly speaking, finding a good way to store passwords has been interesting to say the least. At the current moment of writing this, I have the day off so I am able to try and work on this as much as I can before my work week continues. Learning the stegonagraphic functionality of Stegano's crate is my highest priority, because if I can't even store the bytes into the image then there was no point working on the encryption and decryption functionality. So in that regards, thank you for reading my blog post, and hope to see this project release sometime in the coming months!