Win a copy of Serverless Applications with Node.js this week in the NodeJS forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Bear Bibeault
  • Jeanne Boyarsky
  • paul wheaton
Sheriffs:
  • Junilu Lacar
  • Paul Clapham
  • Knute Snortum
Saloon Keepers:
  • Stephan van Hulst
  • Ron McLeod
  • Tim Moores
  • salvin francis
  • Carey Brown
Bartenders:
  • Tim Holloway
  • Frits Walraven
  • Vijitha Kumara

I want to encrypt strings, save it for later, and decrypt it to read it.  RSS feed

 
Greenhorn
Posts: 12
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello! I have been working on a Employee management system for practice, and after making the core classes, I thought of encrypting the data.  
The problem is, every single place I search talks about symmetrical, one-time encryption and decryption, using the same salt for both and doing it in one run.  
But I want to save it for later use! And I am really lost at EVERYTHING of this. Every help is appreciated, but here are a list of the biggest problems right now.
  • UTF-8 Leaves 3 bytes of data, making it difficult to read the salt. What do I do?
  • Saving happens just fine, but the decryption is not working at the moment.
  • Should I save in bytes or in string? And what is the right way to convert byte to string and vice-versa?

  • Here is the part of my code that handles this.
    (Please ignore the comments. Most of them is for me to not forget what everything does.)
    My localGetter class, that implements getter. Responsible for retrieving and saving data.  

    Thanks in advance.
     
    Saloon Keeper
    Posts: 9997
    208
    • Likes 2
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Simply don't store binary data as text. It's not text. If you REALLY must, then use an encoding that was intended for binary data, such as Base64.

    Don't store passwords. You must always derive a key from the password, and then either store the key in a KeyStore, or if you want the user to enter their password to decrypt a file, regenerate the key by retrieving the key generation parameters (such as the IV) from the file that you encrypted.

    Update your crypto algorithms. DES is old hat. Use AES for symmetric keys and RSA or EC for asymmetric keys. For encryption, ALWAYS use authenticated encryption algorithms, such as AES/GCM.

    Why are you using so much fixed lengths? Why is a password 11 characters? Why is a salt 8 bytes? Why is a message 64 bytes?

    I can see a bunch of mistakes in your code, but it's easier to review it if you've cleaned it up. Rename your classes so they start with an upper-case letter. Using type names such as localSetter makes your code much more difficult to read. Instead of closing your resources manually everywhere, use try-with-resources. Instead of printing out your exceptions everywhere, let them bubble up the stack, optionally wrapped in a new exception type that is appropriate for the abstraction level.

     
    Ranch Hand
    Posts: 505
    Chrome Linux VI Editor
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Doing crypto right is hard.  Check out Bruce Schneier's book Applied Cryptography.  If your library system is anything like mine you can borrow it from there.
     
    F Lucas
    Greenhorn
    Posts: 12
    2
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Thanks to both of you for the reply.  
    I will repost this after I change algorythms and make my code more visible.  
    Should I do it in another post or just use the reply?
     
    Stephan van Hulst
    Saloon Keeper
    Posts: 9997
    208
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    You can just reply here.
     
    F Lucas
    Greenhorn
    Posts: 12
    2
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I changed my encription algorythm to AES.
    Also improved code readability.
    There is a lot of unexplicably hardcoded sections on the encryption, but it is because I am scared of changing anything and it suddently stop working.  
    I just want to get it to work, so I can then improve it later.  
    Also I don't quite understand the keyspecs, so most of it are copy-pasted.  
    This time, I started getting a badtag exception. It encrypts fine, but when decrypting it tells me that it had a tag mismatch.  
    If anybody could help me I would be grateful.


     
    Stephan van Hulst
    Saloon Keeper
    Posts: 9997
    208
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    An AEAD algorithm first encrypts your secret message and then signs the ciphertext. When decrypting, it first verifies the signature to ensure that the ciphertext was not tampered with before it attempts to decrypt it. This is done to prevent chosen ciphertext attacks.

    When you get an AEADBadTagException, it means that the signature could not be verified. This can have various reasons:

  • You're using the wrong key.
  • You're using the wrong initialization vector (salt).
  • You're trying to decrypt a different ciphertext than the ciphertext you got after encryption.
  • The tag length or block size that you specify for the decryption step are not the same as the parameters used in the encryption step.

  • You can very easily debug these issues yourself if you completely separate your formatting/parsing code from your encryption/decryption code.

    Refactor your code so that all code related to encryption/decryption is only concerned with raw binary data. Basically you just want to pass in your entire message as a single byte array, and encrypt that.

    To debug, convert your key, IV and ciphertext to Base64 and print it out after you have encrypted your secret message. Before decrypting, do the same thing. If the Base64 representation of your key, the IV and your ciphertext all match what you got after encrypting, the decryption should occur successfully.

    The problem is likely caused because your encryption and decryption steps are not symmetric: You encrypt your data one key-value pair at a time, but you decrypt the whole ciphertext in one go.

    In the next iteration of the code you post, there should be:

  • NO code related to generating tables, or converting tables to binary data.
  • NO exceptions being printed to the standard error stream.
  • NO useless comments that basically repeat what the code does, such as "Initiates it" or "Writes it to the file".
  • NO calls to flush() or close(). Use try-with-resources.
  •  
    F Lucas
    Greenhorn
    Posts: 12
    2
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Thanks for the reply. Just one more thing. Does it mean I have to
    Export all the formatting code to a separate method
    Make the method symmetric, and make it accept a parameter to change between encryption mode and decryption mode
    Polish the code more
    And print out the Key, salt, and ciphertext in Base64 for debug purposes
    Am I correct? I just wanted to make it sure before starting to work on it.
    Thanks in advance.
    Edit : I use excessive amounts of comments on my code because it helps me remember basic code. But it probably reduces readability, so I will omit it next time.
     
    Stephan van Hulst
    Saloon Keeper
    Posts: 9997
    208
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    F Lucas wrote:Export all the formatting code to a separate method


    Not just a separate method, a whole separate class. There are two, maybe three steps to writing your table in an encrypted form:

  • Serialize the table to binary data.
  • Encrypt the binary data.
  • Optional: Convert the binary data to text.

  • Different classes are responsible for all these steps. Serializing your table to a binary form can be either the responsibility of your table itself, or for a different class that handles all serialization. Encryption is the responsibility of a class that handles encryption for ALL binary data, not just your table. Converting the binary data to text is the responsibility of whatever class wants to write your table in the first place. This could be the table itself, or it could be a different class that is handling a table.

    Make the method symmetric, and make it accept a parameter to change between encryption mode and decryption mode


    No. Make one method for encryption and one method for decryption. By symmetric I mean that the two methods do the same thing, except the inverse operations in the inverse order.

    Polish the code more


    Meh. This is too vague. Any code can be polished. When is it enough?

    And print out the Key, salt, and ciphertext in Base64 for debug purposes


    Yes, but ONLY until you find the source of the issue. It is obvious that the key should normally never be printed, and some people consider the IV to be secret as well, though I'm not one of them.

    I use excessive amounts of comments on my code because it helps me remember basic code. But it probably reduces readability, so I will omit it next time.


    If you need comments to help you remember what a piece of code does and why, then it's a sign that you need to extract that piece of code and make it into a separate (private) method. This will make your code self-documenting.
     
    F Lucas
    Greenhorn
    Posts: 12
    2
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Amazing, detailed answer. Thank you.
     
    F Lucas
    Greenhorn
    Posts: 12
    2
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Thank you Stephan. After changing the methods and double checking everything, I noticed a few things.
    And it now works!
    I will leave everything I did to make it work here.
    1. I was only saving the value from .doFinal() and that was wrong.
    FIX: Use .update() first, save into an array, and concatenate the two arrays with arraycopy.
    2. Apparently When using base64 and encryption together, encoding first is wrong.
    FIX: Encrypt first, then encode. Then decode before decrypting.
    3. No more inconsistencies on the input and output. But now it gave me a tag mismatch error.
    FIX: I had to extract the authentication tag (16 bytes in the end of the ciphertext) and use .doFinal
    with it as parameter to make it verify the tag.
    I learned a lot from debugging this. Again, thank you for the tips.  
    I hope you have a VERY nice day!
     
    Stephan van Hulst
    Saloon Keeper
    Posts: 9997
    208
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    You are very welcome, and congratulations on working it out!

    F Lucas wrote:FIX: I had to extract the authentication tag (16 bytes in the end of the ciphertext) and use .doFinal
    with it as parameter to make it verify the tag.


    I don't think that is correct. The authentication tag is automatically extracted by the GCM algorithm. I think what you meant was the initialization vector (or salt, as you call it).

    Can you show us your final code? We might suggest some more improvements.
     
    today's feeble attempt to support the empire
    global solutions you can do at home or in your backyard
    https://www.kickstarter.com/projects/paulwheaton/better-world-boo
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!