AES CTR mode encryption with HMACAES encryption in PHPAES encryption wrapperAES CTR mode using pycryptoAES...

Is it wise to focus on putting odd beats on left when playing double bass drums?

A poker game description that does not feel gimmicky

What is the meaning of "of trouble" in the following sentence?

Can I legally use front facing blue light in the UK?

Is this food a bread or a loaf?

How to move the player while also allowing forces to affect it

Is there a name of the flying bionic bird?

How could a lack of term limits lead to a "dictatorship?"

"My colleague's body is amazing"

Unbreakable Formation vs. Cry of the Carnarium

Copycat chess is back

Is "plugging out" electronic devices an American expression?

Manga about a female worker who got dragged into another world together with this high school girl and she was just told she's not needed anymore

How to make payment on the internet without leaving a money trail?

Are white and non-white police officers equally likely to kill black suspects?

Could a US political party gain complete control over the government by removing checks & balances?

COUNT(*) or MAX(id) - which is faster?

Information to fellow intern about hiring?

Why was the "bread communication" in the arena of Catching Fire left out in the movie?

What does it exactly mean if a random variable follows a distribution

What does 'script /dev/null' do?

Does it makes sense to buy a new cycle to learn riding?

extract characters between two commas?

Email Account under attack (really) - anything I can do?



AES CTR mode encryption with HMAC


AES encryption in PHPAES encryption wrapperAES CTR mode using pycryptoAES encryption classRecreating binary counter for arbitrary length arraysEncrypting a binary stream with RSA + AES in counter modeEncryption algorithm using CTR modeEncrypt and decrypt a message using AES-256 with GCM mode using Bouncy Castle C# libraryPyCrypto AES-CFB with SCrypt and HMACJava AES file encryption/decryption






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







2












$begingroup$


I am trying to implement AES CTR encryption mode with HMAC authentication for messages.



It's encrypting and decrypting fine as long as the key length is 64 bytes, since AES key and HMAC key are being derived from this key.



Questions




  • Is it safe to append IV or nonce to the encrypted messages?

  • Is it safe to append HMAC digest to append to the messages?

  • Can you review it for best security coding practices?
    I am using Pycryptodome


Code



import os 
import zlib
from Crypto.Hash import HMAC
from Crypto.Hash import SHA256
from Crypto.Cipher import AES
from Crypto.Util import Counter
import zlib
def encrypt(full_key, plaintext):

if len(full_key) != 64:
raise Exception("FULL key length shall be equal to 64")
key = full_key[:len(full_key) //2]

# Use the last half as the HMAC key
hmac_key = full_key[len(full_key) // 2:]


if isinstance(plaintext, str):
plaintext = plaintext.encode()

compressed = zlib.compress(plaintext, 5)
print (f"compressed plaintext {compressed}")



# Choose a random, 16-byte IV.
iv = os.urandom(16)
# Convert the IV to a Python integer.
iv_int = int(binascii.hexlify(iv), 16)
# Create a new Counter object with IV = iv_int.
ctr = Counter.new(128, initial_value=iv_int)
# Create AES-CTR cipher.
aes = AES.new(key, AES.MODE_CTR, counter=ctr)
# Encrypt and return IV and ciphertext.
ciphertext = aes.encrypt(compressed)


hmac_obj = HMAC.new(hmac_key, compressed, SHA256)
mac = hmac_obj.digest()

return iv+ciphertext+mac


def decrypt(key, ciphertext):
# Initialize counter for decryption. iv should be the same as the output of
# encrypt().


if len(full_key) != 64:
raise Exception("FULL key length shall be equal to 64")

key = full_key[:len(full_key) //2]

# Use the last half as the HMAC key
hmac_key = full_key[len(full_key) // 2:]

mac_length = 32
iv_length = 16
iv = ciphertext[:16]
mac = ciphertext[-mac_length:]

_ciphertext = ciphertext[iv_length:-mac_length]


iv_int = int(iv.hex(), 16)
ctr = Counter.new(128, initial_value=iv_int)
# Create AES-CTR cipher.
aes = AES.new(key, AES.MODE_CTR, counter=ctr)

ciphertext = aes.decrypt(_ciphertext)

# Extract the MAC from the end of the file
hmac_obj = HMAC.new(hmac_key, ciphertext, SHA256)
computed_mac = hmac_obj.digest()

if computed_mac != mac:
raise Exception("Messege integrity violated")





plaintext= zlib.decompress(ciphertext)

# Decrypt and return the plaintext.


return plaintext









share|improve this question









New contributor




saurav verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$



















    2












    $begingroup$


    I am trying to implement AES CTR encryption mode with HMAC authentication for messages.



    It's encrypting and decrypting fine as long as the key length is 64 bytes, since AES key and HMAC key are being derived from this key.



    Questions




    • Is it safe to append IV or nonce to the encrypted messages?

    • Is it safe to append HMAC digest to append to the messages?

    • Can you review it for best security coding practices?
      I am using Pycryptodome


    Code



    import os 
    import zlib
    from Crypto.Hash import HMAC
    from Crypto.Hash import SHA256
    from Crypto.Cipher import AES
    from Crypto.Util import Counter
    import zlib
    def encrypt(full_key, plaintext):

    if len(full_key) != 64:
    raise Exception("FULL key length shall be equal to 64")
    key = full_key[:len(full_key) //2]

    # Use the last half as the HMAC key
    hmac_key = full_key[len(full_key) // 2:]


    if isinstance(plaintext, str):
    plaintext = plaintext.encode()

    compressed = zlib.compress(plaintext, 5)
    print (f"compressed plaintext {compressed}")



    # Choose a random, 16-byte IV.
    iv = os.urandom(16)
    # Convert the IV to a Python integer.
    iv_int = int(binascii.hexlify(iv), 16)
    # Create a new Counter object with IV = iv_int.
    ctr = Counter.new(128, initial_value=iv_int)
    # Create AES-CTR cipher.
    aes = AES.new(key, AES.MODE_CTR, counter=ctr)
    # Encrypt and return IV and ciphertext.
    ciphertext = aes.encrypt(compressed)


    hmac_obj = HMAC.new(hmac_key, compressed, SHA256)
    mac = hmac_obj.digest()

    return iv+ciphertext+mac


    def decrypt(key, ciphertext):
    # Initialize counter for decryption. iv should be the same as the output of
    # encrypt().


    if len(full_key) != 64:
    raise Exception("FULL key length shall be equal to 64")

    key = full_key[:len(full_key) //2]

    # Use the last half as the HMAC key
    hmac_key = full_key[len(full_key) // 2:]

    mac_length = 32
    iv_length = 16
    iv = ciphertext[:16]
    mac = ciphertext[-mac_length:]

    _ciphertext = ciphertext[iv_length:-mac_length]


    iv_int = int(iv.hex(), 16)
    ctr = Counter.new(128, initial_value=iv_int)
    # Create AES-CTR cipher.
    aes = AES.new(key, AES.MODE_CTR, counter=ctr)

    ciphertext = aes.decrypt(_ciphertext)

    # Extract the MAC from the end of the file
    hmac_obj = HMAC.new(hmac_key, ciphertext, SHA256)
    computed_mac = hmac_obj.digest()

    if computed_mac != mac:
    raise Exception("Messege integrity violated")





    plaintext= zlib.decompress(ciphertext)

    # Decrypt and return the plaintext.


    return plaintext









    share|improve this question









    New contributor




    saurav verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.







    $endgroup$















      2












      2








      2





      $begingroup$


      I am trying to implement AES CTR encryption mode with HMAC authentication for messages.



      It's encrypting and decrypting fine as long as the key length is 64 bytes, since AES key and HMAC key are being derived from this key.



      Questions




      • Is it safe to append IV or nonce to the encrypted messages?

      • Is it safe to append HMAC digest to append to the messages?

      • Can you review it for best security coding practices?
        I am using Pycryptodome


      Code



      import os 
      import zlib
      from Crypto.Hash import HMAC
      from Crypto.Hash import SHA256
      from Crypto.Cipher import AES
      from Crypto.Util import Counter
      import zlib
      def encrypt(full_key, plaintext):

      if len(full_key) != 64:
      raise Exception("FULL key length shall be equal to 64")
      key = full_key[:len(full_key) //2]

      # Use the last half as the HMAC key
      hmac_key = full_key[len(full_key) // 2:]


      if isinstance(plaintext, str):
      plaintext = plaintext.encode()

      compressed = zlib.compress(plaintext, 5)
      print (f"compressed plaintext {compressed}")



      # Choose a random, 16-byte IV.
      iv = os.urandom(16)
      # Convert the IV to a Python integer.
      iv_int = int(binascii.hexlify(iv), 16)
      # Create a new Counter object with IV = iv_int.
      ctr = Counter.new(128, initial_value=iv_int)
      # Create AES-CTR cipher.
      aes = AES.new(key, AES.MODE_CTR, counter=ctr)
      # Encrypt and return IV and ciphertext.
      ciphertext = aes.encrypt(compressed)


      hmac_obj = HMAC.new(hmac_key, compressed, SHA256)
      mac = hmac_obj.digest()

      return iv+ciphertext+mac


      def decrypt(key, ciphertext):
      # Initialize counter for decryption. iv should be the same as the output of
      # encrypt().


      if len(full_key) != 64:
      raise Exception("FULL key length shall be equal to 64")

      key = full_key[:len(full_key) //2]

      # Use the last half as the HMAC key
      hmac_key = full_key[len(full_key) // 2:]

      mac_length = 32
      iv_length = 16
      iv = ciphertext[:16]
      mac = ciphertext[-mac_length:]

      _ciphertext = ciphertext[iv_length:-mac_length]


      iv_int = int(iv.hex(), 16)
      ctr = Counter.new(128, initial_value=iv_int)
      # Create AES-CTR cipher.
      aes = AES.new(key, AES.MODE_CTR, counter=ctr)

      ciphertext = aes.decrypt(_ciphertext)

      # Extract the MAC from the end of the file
      hmac_obj = HMAC.new(hmac_key, ciphertext, SHA256)
      computed_mac = hmac_obj.digest()

      if computed_mac != mac:
      raise Exception("Messege integrity violated")





      plaintext= zlib.decompress(ciphertext)

      # Decrypt and return the plaintext.


      return plaintext









      share|improve this question









      New contributor




      saurav verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.







      $endgroup$




      I am trying to implement AES CTR encryption mode with HMAC authentication for messages.



      It's encrypting and decrypting fine as long as the key length is 64 bytes, since AES key and HMAC key are being derived from this key.



      Questions




      • Is it safe to append IV or nonce to the encrypted messages?

      • Is it safe to append HMAC digest to append to the messages?

      • Can you review it for best security coding practices?
        I am using Pycryptodome


      Code



      import os 
      import zlib
      from Crypto.Hash import HMAC
      from Crypto.Hash import SHA256
      from Crypto.Cipher import AES
      from Crypto.Util import Counter
      import zlib
      def encrypt(full_key, plaintext):

      if len(full_key) != 64:
      raise Exception("FULL key length shall be equal to 64")
      key = full_key[:len(full_key) //2]

      # Use the last half as the HMAC key
      hmac_key = full_key[len(full_key) // 2:]


      if isinstance(plaintext, str):
      plaintext = plaintext.encode()

      compressed = zlib.compress(plaintext, 5)
      print (f"compressed plaintext {compressed}")



      # Choose a random, 16-byte IV.
      iv = os.urandom(16)
      # Convert the IV to a Python integer.
      iv_int = int(binascii.hexlify(iv), 16)
      # Create a new Counter object with IV = iv_int.
      ctr = Counter.new(128, initial_value=iv_int)
      # Create AES-CTR cipher.
      aes = AES.new(key, AES.MODE_CTR, counter=ctr)
      # Encrypt and return IV and ciphertext.
      ciphertext = aes.encrypt(compressed)


      hmac_obj = HMAC.new(hmac_key, compressed, SHA256)
      mac = hmac_obj.digest()

      return iv+ciphertext+mac


      def decrypt(key, ciphertext):
      # Initialize counter for decryption. iv should be the same as the output of
      # encrypt().


      if len(full_key) != 64:
      raise Exception("FULL key length shall be equal to 64")

      key = full_key[:len(full_key) //2]

      # Use the last half as the HMAC key
      hmac_key = full_key[len(full_key) // 2:]

      mac_length = 32
      iv_length = 16
      iv = ciphertext[:16]
      mac = ciphertext[-mac_length:]

      _ciphertext = ciphertext[iv_length:-mac_length]


      iv_int = int(iv.hex(), 16)
      ctr = Counter.new(128, initial_value=iv_int)
      # Create AES-CTR cipher.
      aes = AES.new(key, AES.MODE_CTR, counter=ctr)

      ciphertext = aes.decrypt(_ciphertext)

      # Extract the MAC from the end of the file
      hmac_obj = HMAC.new(hmac_key, ciphertext, SHA256)
      computed_mac = hmac_obj.digest()

      if computed_mac != mac:
      raise Exception("Messege integrity violated")





      plaintext= zlib.decompress(ciphertext)

      # Decrypt and return the plaintext.


      return plaintext






      python python-3.x security authentication aes






      share|improve this question









      New contributor




      saurav verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      saurav verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 7 hours ago







      saurav verma













      New contributor




      saurav verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked yesterday









      saurav vermasaurav verma

      1115




      1115




      New contributor




      saurav verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      saurav verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      saurav verma is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















          1 Answer
          1






          active

          oldest

          votes


















          0












          $begingroup$

          I'm not a security expert, so my review will focus on general best practices first.



          Code structure and style



          1. Imports

          You can group import that belong together, e.g



          from Crypto.Hash import HMAC
          from Crypto.Hash import SHA256


          can be written as



          from Crypto.Hash import HMAC, SHA256


          The Official Style Guide for Python also recommends to place import from the standard library before any third party libraries. Apart from the double import of zlib you're already following this.



          2. Documentation

          You started to add some kind of documentation on decrypt, so encrypt should be treated the same. The officially recommended way is to provide function documentation surrounded by """...""" like so



          def decrypt(key, ciphertext):
          """Initialize counter for decryption.

          iv should be the same as the output of encrypt().
          """
          #^--- you probably also mean ciphertext here


          This will also allow Python's built-in help(...) function to pick up your documentation.



          3. Whitespace

          You should tidy up the newlines in your code. There are often two (sometimes more) newlines within a function's body, while there are none between the imports and functions. This might be an issue from posting the code here on Code Review, but you should definitely check that. A reasonable convention many people agree on is to use two newlines to seperate functions (or imports from the following functions) and only use a single newline in function bodys to visually create logical groups of code.



          The code itself



          1. Exceptions

          "You're not doing the right thing!" What thing you might ask? Well, ... "Read it! Find it out yourself!"

          Sounds frustrating, doesn't it? Python offers a wide variety of built-in exceptions so you can easily convey the type of error that has happened, without the need to parse/read the actual error message. In your case ValueError seems to be appropriate. From the documentation:




          exception ValueError
          Raised when an operation or function receives an argument that has the right type but an inappropriate value, [...]




          In case of an error on checking the HMAC, you might add your own exception derived from Exception (maybe HMACValidationError?). I will leave this as an exercise to you.



          2. encrypt/decrypt

          These functions look quite reasonable from what I can jugde and work the way I would expect them to work. A minor "issue" I found, is that they are not handling string encoding/decoding symmetrically. While encrypt does handle unicode strings by converting them to bytes representation before encryption, decrypt has no way of knowing that this step has taken place and will always return the raw bytes.

          At the moment, I would favor an approach where the application using those functions has to take care that the input is already encoded into bytes and also decode the bytes back into a unicode string if desired. This would also be in line with not handling string values for the key, which strongly hints that there is an earlier step where those are created and possibly encoded.



          3. Security

          From what I've seen on my journey through cryptoland, it is a quite common practice to simply prepend the ciphertext with the initialiation vector (IV). Password hashing functions do something similar and tend to store the salt prepended to the actual hash to have it available for validation later. Remember: the IV does not protect your ciphertext in the same way the key does, and therefore must not be handled with the same care. It instead prevents an attacker to see the same plaintext mapped the same ciphertext repeatedly, which is maybe more than you can afford to reveal.

          Something similar applys to the HMAC. The security of the HMAC authentication should only rely on the secrecy of the key, and nothing else. So as long as you use a suitable HMAC implementation and a reasonably secure key, you should be good to go. Just bear in mind that an HMAC alone does not and cannot prevent all kind of attacks, e.g. HMAC alone cannot prevent replay.






          share|improve this answer









          $endgroup$














            Your Answer





            StackExchange.ifUsing("editor", function () {
            return StackExchange.using("mathjaxEditing", function () {
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            });
            });
            }, "mathjax-editing");

            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "196"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });






            saurav verma is a new contributor. Be nice, and check out our Code of Conduct.










            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f217014%2faes-ctr-mode-encryption-with-hmac%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            0












            $begingroup$

            I'm not a security expert, so my review will focus on general best practices first.



            Code structure and style



            1. Imports

            You can group import that belong together, e.g



            from Crypto.Hash import HMAC
            from Crypto.Hash import SHA256


            can be written as



            from Crypto.Hash import HMAC, SHA256


            The Official Style Guide for Python also recommends to place import from the standard library before any third party libraries. Apart from the double import of zlib you're already following this.



            2. Documentation

            You started to add some kind of documentation on decrypt, so encrypt should be treated the same. The officially recommended way is to provide function documentation surrounded by """...""" like so



            def decrypt(key, ciphertext):
            """Initialize counter for decryption.

            iv should be the same as the output of encrypt().
            """
            #^--- you probably also mean ciphertext here


            This will also allow Python's built-in help(...) function to pick up your documentation.



            3. Whitespace

            You should tidy up the newlines in your code. There are often two (sometimes more) newlines within a function's body, while there are none between the imports and functions. This might be an issue from posting the code here on Code Review, but you should definitely check that. A reasonable convention many people agree on is to use two newlines to seperate functions (or imports from the following functions) and only use a single newline in function bodys to visually create logical groups of code.



            The code itself



            1. Exceptions

            "You're not doing the right thing!" What thing you might ask? Well, ... "Read it! Find it out yourself!"

            Sounds frustrating, doesn't it? Python offers a wide variety of built-in exceptions so you can easily convey the type of error that has happened, without the need to parse/read the actual error message. In your case ValueError seems to be appropriate. From the documentation:




            exception ValueError
            Raised when an operation or function receives an argument that has the right type but an inappropriate value, [...]




            In case of an error on checking the HMAC, you might add your own exception derived from Exception (maybe HMACValidationError?). I will leave this as an exercise to you.



            2. encrypt/decrypt

            These functions look quite reasonable from what I can jugde and work the way I would expect them to work. A minor "issue" I found, is that they are not handling string encoding/decoding symmetrically. While encrypt does handle unicode strings by converting them to bytes representation before encryption, decrypt has no way of knowing that this step has taken place and will always return the raw bytes.

            At the moment, I would favor an approach where the application using those functions has to take care that the input is already encoded into bytes and also decode the bytes back into a unicode string if desired. This would also be in line with not handling string values for the key, which strongly hints that there is an earlier step where those are created and possibly encoded.



            3. Security

            From what I've seen on my journey through cryptoland, it is a quite common practice to simply prepend the ciphertext with the initialiation vector (IV). Password hashing functions do something similar and tend to store the salt prepended to the actual hash to have it available for validation later. Remember: the IV does not protect your ciphertext in the same way the key does, and therefore must not be handled with the same care. It instead prevents an attacker to see the same plaintext mapped the same ciphertext repeatedly, which is maybe more than you can afford to reveal.

            Something similar applys to the HMAC. The security of the HMAC authentication should only rely on the secrecy of the key, and nothing else. So as long as you use a suitable HMAC implementation and a reasonably secure key, you should be good to go. Just bear in mind that an HMAC alone does not and cannot prevent all kind of attacks, e.g. HMAC alone cannot prevent replay.






            share|improve this answer









            $endgroup$


















              0












              $begingroup$

              I'm not a security expert, so my review will focus on general best practices first.



              Code structure and style



              1. Imports

              You can group import that belong together, e.g



              from Crypto.Hash import HMAC
              from Crypto.Hash import SHA256


              can be written as



              from Crypto.Hash import HMAC, SHA256


              The Official Style Guide for Python also recommends to place import from the standard library before any third party libraries. Apart from the double import of zlib you're already following this.



              2. Documentation

              You started to add some kind of documentation on decrypt, so encrypt should be treated the same. The officially recommended way is to provide function documentation surrounded by """...""" like so



              def decrypt(key, ciphertext):
              """Initialize counter for decryption.

              iv should be the same as the output of encrypt().
              """
              #^--- you probably also mean ciphertext here


              This will also allow Python's built-in help(...) function to pick up your documentation.



              3. Whitespace

              You should tidy up the newlines in your code. There are often two (sometimes more) newlines within a function's body, while there are none between the imports and functions. This might be an issue from posting the code here on Code Review, but you should definitely check that. A reasonable convention many people agree on is to use two newlines to seperate functions (or imports from the following functions) and only use a single newline in function bodys to visually create logical groups of code.



              The code itself



              1. Exceptions

              "You're not doing the right thing!" What thing you might ask? Well, ... "Read it! Find it out yourself!"

              Sounds frustrating, doesn't it? Python offers a wide variety of built-in exceptions so you can easily convey the type of error that has happened, without the need to parse/read the actual error message. In your case ValueError seems to be appropriate. From the documentation:




              exception ValueError
              Raised when an operation or function receives an argument that has the right type but an inappropriate value, [...]




              In case of an error on checking the HMAC, you might add your own exception derived from Exception (maybe HMACValidationError?). I will leave this as an exercise to you.



              2. encrypt/decrypt

              These functions look quite reasonable from what I can jugde and work the way I would expect them to work. A minor "issue" I found, is that they are not handling string encoding/decoding symmetrically. While encrypt does handle unicode strings by converting them to bytes representation before encryption, decrypt has no way of knowing that this step has taken place and will always return the raw bytes.

              At the moment, I would favor an approach where the application using those functions has to take care that the input is already encoded into bytes and also decode the bytes back into a unicode string if desired. This would also be in line with not handling string values for the key, which strongly hints that there is an earlier step where those are created and possibly encoded.



              3. Security

              From what I've seen on my journey through cryptoland, it is a quite common practice to simply prepend the ciphertext with the initialiation vector (IV). Password hashing functions do something similar and tend to store the salt prepended to the actual hash to have it available for validation later. Remember: the IV does not protect your ciphertext in the same way the key does, and therefore must not be handled with the same care. It instead prevents an attacker to see the same plaintext mapped the same ciphertext repeatedly, which is maybe more than you can afford to reveal.

              Something similar applys to the HMAC. The security of the HMAC authentication should only rely on the secrecy of the key, and nothing else. So as long as you use a suitable HMAC implementation and a reasonably secure key, you should be good to go. Just bear in mind that an HMAC alone does not and cannot prevent all kind of attacks, e.g. HMAC alone cannot prevent replay.






              share|improve this answer









              $endgroup$
















                0












                0








                0





                $begingroup$

                I'm not a security expert, so my review will focus on general best practices first.



                Code structure and style



                1. Imports

                You can group import that belong together, e.g



                from Crypto.Hash import HMAC
                from Crypto.Hash import SHA256


                can be written as



                from Crypto.Hash import HMAC, SHA256


                The Official Style Guide for Python also recommends to place import from the standard library before any third party libraries. Apart from the double import of zlib you're already following this.



                2. Documentation

                You started to add some kind of documentation on decrypt, so encrypt should be treated the same. The officially recommended way is to provide function documentation surrounded by """...""" like so



                def decrypt(key, ciphertext):
                """Initialize counter for decryption.

                iv should be the same as the output of encrypt().
                """
                #^--- you probably also mean ciphertext here


                This will also allow Python's built-in help(...) function to pick up your documentation.



                3. Whitespace

                You should tidy up the newlines in your code. There are often two (sometimes more) newlines within a function's body, while there are none between the imports and functions. This might be an issue from posting the code here on Code Review, but you should definitely check that. A reasonable convention many people agree on is to use two newlines to seperate functions (or imports from the following functions) and only use a single newline in function bodys to visually create logical groups of code.



                The code itself



                1. Exceptions

                "You're not doing the right thing!" What thing you might ask? Well, ... "Read it! Find it out yourself!"

                Sounds frustrating, doesn't it? Python offers a wide variety of built-in exceptions so you can easily convey the type of error that has happened, without the need to parse/read the actual error message. In your case ValueError seems to be appropriate. From the documentation:




                exception ValueError
                Raised when an operation or function receives an argument that has the right type but an inappropriate value, [...]




                In case of an error on checking the HMAC, you might add your own exception derived from Exception (maybe HMACValidationError?). I will leave this as an exercise to you.



                2. encrypt/decrypt

                These functions look quite reasonable from what I can jugde and work the way I would expect them to work. A minor "issue" I found, is that they are not handling string encoding/decoding symmetrically. While encrypt does handle unicode strings by converting them to bytes representation before encryption, decrypt has no way of knowing that this step has taken place and will always return the raw bytes.

                At the moment, I would favor an approach where the application using those functions has to take care that the input is already encoded into bytes and also decode the bytes back into a unicode string if desired. This would also be in line with not handling string values for the key, which strongly hints that there is an earlier step where those are created and possibly encoded.



                3. Security

                From what I've seen on my journey through cryptoland, it is a quite common practice to simply prepend the ciphertext with the initialiation vector (IV). Password hashing functions do something similar and tend to store the salt prepended to the actual hash to have it available for validation later. Remember: the IV does not protect your ciphertext in the same way the key does, and therefore must not be handled with the same care. It instead prevents an attacker to see the same plaintext mapped the same ciphertext repeatedly, which is maybe more than you can afford to reveal.

                Something similar applys to the HMAC. The security of the HMAC authentication should only rely on the secrecy of the key, and nothing else. So as long as you use a suitable HMAC implementation and a reasonably secure key, you should be good to go. Just bear in mind that an HMAC alone does not and cannot prevent all kind of attacks, e.g. HMAC alone cannot prevent replay.






                share|improve this answer









                $endgroup$



                I'm not a security expert, so my review will focus on general best practices first.



                Code structure and style



                1. Imports

                You can group import that belong together, e.g



                from Crypto.Hash import HMAC
                from Crypto.Hash import SHA256


                can be written as



                from Crypto.Hash import HMAC, SHA256


                The Official Style Guide for Python also recommends to place import from the standard library before any third party libraries. Apart from the double import of zlib you're already following this.



                2. Documentation

                You started to add some kind of documentation on decrypt, so encrypt should be treated the same. The officially recommended way is to provide function documentation surrounded by """...""" like so



                def decrypt(key, ciphertext):
                """Initialize counter for decryption.

                iv should be the same as the output of encrypt().
                """
                #^--- you probably also mean ciphertext here


                This will also allow Python's built-in help(...) function to pick up your documentation.



                3. Whitespace

                You should tidy up the newlines in your code. There are often two (sometimes more) newlines within a function's body, while there are none between the imports and functions. This might be an issue from posting the code here on Code Review, but you should definitely check that. A reasonable convention many people agree on is to use two newlines to seperate functions (or imports from the following functions) and only use a single newline in function bodys to visually create logical groups of code.



                The code itself



                1. Exceptions

                "You're not doing the right thing!" What thing you might ask? Well, ... "Read it! Find it out yourself!"

                Sounds frustrating, doesn't it? Python offers a wide variety of built-in exceptions so you can easily convey the type of error that has happened, without the need to parse/read the actual error message. In your case ValueError seems to be appropriate. From the documentation:




                exception ValueError
                Raised when an operation or function receives an argument that has the right type but an inappropriate value, [...]




                In case of an error on checking the HMAC, you might add your own exception derived from Exception (maybe HMACValidationError?). I will leave this as an exercise to you.



                2. encrypt/decrypt

                These functions look quite reasonable from what I can jugde and work the way I would expect them to work. A minor "issue" I found, is that they are not handling string encoding/decoding symmetrically. While encrypt does handle unicode strings by converting them to bytes representation before encryption, decrypt has no way of knowing that this step has taken place and will always return the raw bytes.

                At the moment, I would favor an approach where the application using those functions has to take care that the input is already encoded into bytes and also decode the bytes back into a unicode string if desired. This would also be in line with not handling string values for the key, which strongly hints that there is an earlier step where those are created and possibly encoded.



                3. Security

                From what I've seen on my journey through cryptoland, it is a quite common practice to simply prepend the ciphertext with the initialiation vector (IV). Password hashing functions do something similar and tend to store the salt prepended to the actual hash to have it available for validation later. Remember: the IV does not protect your ciphertext in the same way the key does, and therefore must not be handled with the same care. It instead prevents an attacker to see the same plaintext mapped the same ciphertext repeatedly, which is maybe more than you can afford to reveal.

                Something similar applys to the HMAC. The security of the HMAC authentication should only rely on the secrecy of the key, and nothing else. So as long as you use a suitable HMAC implementation and a reasonably secure key, you should be good to go. Just bear in mind that an HMAC alone does not and cannot prevent all kind of attacks, e.g. HMAC alone cannot prevent replay.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered 3 hours ago









                AlexAlex

                1,333419




                1,333419






















                    saurav verma is a new contributor. Be nice, and check out our Code of Conduct.










                    draft saved

                    draft discarded


















                    saurav verma is a new contributor. Be nice, and check out our Code of Conduct.













                    saurav verma is a new contributor. Be nice, and check out our Code of Conduct.












                    saurav verma is a new contributor. Be nice, and check out our Code of Conduct.
















                    Thanks for contributing an answer to Code Review Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    Use MathJax to format equations. MathJax reference.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f217014%2faes-ctr-mode-encryption-with-hmac%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    is 'sed' thread safeWhat should someone know about using Python scripts in the shell?Nexenta bash script uses...

                    How do i solve the “ No module named 'mlxtend' ” issue on Jupyter?

                    Pilgersdorf Inhaltsverzeichnis Geografie | Geschichte | Bevölkerungsentwicklung | Politik | Kultur...