Thanks for the clarification.

On Sat, Jan 4, 2025 at 2:59 PM Alex Gaynor <alex.gay...@gmail.com> wrote:

> It's correct that nonces do not need to be secret.
>
> Alex
>
> On Sat, Jan 4, 2025 at 5:56 PM Sriram R <sramac...@gmail.com> wrote:
> >
> > Alex,
> >
> > Found the flaw in the code logic, it had to do with the location of the
> nonce file. I was storing the nonce file in the same directory that was
> getting encrypted/decrypted.
> > Once I changed the nonce file location to be outside the target
> directory, the encryption and decryption works flawlessly now.
> >
> > One last question, I read that the nonce file contents are not sensitive
> and it doesn't need to be encrypted. Is that your understanding also?
> >
> > Best,
> > PE
> >
> > On Sat, Jan 4, 2025 at 2:37 PM Sriram R <sramac...@gmail.com> wrote:
> >>
> >> Fair point, here's the entire code:
> >>
> >> import cryptography
> >> from cryptography.fernet import Fernet
> >> from cryptography.hazmat.primitives.kdf.scrypt import Scrypt
> >> import secrets, base64, getpass, os, os.path, argparse
> >>
> >> from cryptography.hazmat.primitives.ciphers.aead import AESGCMSIV
> >>
> >> from pathlib import Path
> >>
> >> from collections import defaultdict, OrderedDict
> >>
> >> aad = b"super secret authenticated but unencrypted data"
> >>
> >> rootpath = "/tmp/cstore/"
> >> #rootpath = "/tmp/certstore/"
> >> #dirs = ['certs/', 'csrs/', 'keys/']
> >> dirs = ['csrs/']
> >> files = []
> >>
> >> saltfile = Path.home().joinpath("salt.salt")
> >> keyfile = Path.home().joinpath(".key")
> >> saltsize = int(32)
> >>
> >> def lsdir(path):
> >>   for nodes in Path(path).iterdir():
> >>      if nodes.is_dir():
> >>          #print("Dir is: ", nodes)
> >>          lsdir(nodes)
> >>      else:
> >>          #print("File is: ", nodes)
> >>          files.append(nodes)
> >>
> >> def gen_salt(size=32):
> >>   return secrets.token_bytes(size)
> >>
> >> def der_key(salt, password):
> >>   kdf = Scrypt(salt=salt, length=32, n=2**20, r=8, p=1)
> >>   return kdf.derive(password.encode())
> >>
> >> def gen_symmkey(salt, password):
> >>   symmkey = der_key(salt, password)
> >>   return symmkey
> >>   #return base64.urlsafe_b64encode(symmkey)
> >>
> >> def encrypt(nonce, fname, aesgcmsiv):
> >>   with open(fname, "rb") as infile:
> >>     file_data = infile.read()
> >>
> >>   # encrypt data
> >>   edata = aesgcmsiv.encrypt(nonce, file_data, aad)
> >>   with open(fname, "wb") as outfile:
> >>      outfile.write(edata)
> >>
> >>
> >> def decrypt(nonce, fname, aesgcmsiv):
> >>   with open(fname, "rb") as infile:
> >>     edata = infile.read()
> >>
> >>   try:
> >>     data = aesgcmsiv.decrypt(nonce, edata, aad)
> >>   except cryptography.exceptions.InvalidTag:
> >>     print("something went wrong")
> >>     return False
> >>
> >>   with open(fname, "wb") as outfile:
> >>      outfile.write(data)
> >>
> >> def call_crypto(saltsize, password):
> >>    if os.path.isfile(saltfile):
> >>      salt = open(saltfile, 'rb').read()
> >>    else:
> >>      salt = gen_salt(saltsize)
> >>      with open(saltfile, 'wb') as sfile:
> >>         sfile.write(salt)
> >>
> >>    key = gen_symmkey(salt, password)
> >>    aesgcmsiv = AESGCMSIV(key)
> >>
> >>     # dir walk and store files to process in a list
> >>    lsdir(rootpath)
> >>
> >>    # encrypt/decrypt all elements in the 'files' list
> >>    if ENC:
> >>      for file in files:
> >>        nonce = os.urandom(12)
> >>        encrypt(nonce, file, aesgcmsiv)
> >>        #nfile = Path.joinpath(file, ".nonce")
> >>        nfile = "/tmp/cstore/csrs/eud1.csr.nonce"
> >>        with open(nfile, 'wb') as f:
> >>          f.write(nonce)
> >>    else:
> >>        for file in files:
> >>          #nfile = Path.joinpath(file, ".nonce")
> >>          nfile = "/tmp/cstore/csrs/eud1.csr.nonce"
> >>          with open(nfile, 'rb') as f:
> >>            nonce = f.read()
> >>            decrypt(nonce, file, aesgcmsiv)
> >>
> >> if __name__ == "__main__":
> >>
> >>    password = some_password
> >>
> >>    ENC = False
> >>    call_crypto(saltsize, password)
> >>
> >> Best,
> >> PE
> >>
> >> On Sat, Jan 4, 2025 at 2:32 PM Sriram R <sramac...@gmail.com> wrote:
> >>>
> >>> Fair point, here's the entire code:
> >>>
> >>> [certadmin@r9kc01-silver ~]$ !source
> >>> source ./testvenv/bin/activate
> >>> (testvenv) [certadmin@r9kc01-silver ~]$ vi ./gcm.py
> >>> (testvenv) [certadmin@r9kc01-silver ~]$ cat !$
> >>> cat ./gcm.py
> >>> import cryptography
> >>> from cryptography.fernet import Fernet
> >>> from cryptography.hazmat.primitives.kdf.scrypt import Scrypt
> >>> import secrets, base64, getpass, os, os.path, argparse
> >>>
> >>> from cryptography.hazmat.primitives.ciphers.aead import AESGCMSIV
> >>>
> >>> from pathlib import Path
> >>>
> >>> from collections import defaultdict, OrderedDict
> >>>
> >>> aad = b"super secret authenticated but unencrypted data"
> >>>
> >>> rootpath = "/tmp/cstore/"
> >>> #rootpath = "/tmp/certstore/"
> >>> #dirs = ['certs/', 'csrs/', 'keys/']
> >>> dirs = ['csrs/']
> >>> files = []
> >>>
> >>> saltfile = Path.home().joinpath("salt.salt")
> >>> keyfile = Path.home().joinpath(".key")
> >>> saltsize = int(32)
> >>>
> >>> def lsdir(path):
> >>>   for nodes in Path(path).iterdir():
> >>>      if nodes.is_dir():
> >>>          #print("Dir is: ", nodes)
> >>>          lsdir(nodes)
> >>>      else:
> >>>          #print("File is: ", nodes)
> >>>          files.append(nodes)
> >>>
> >>> def gen_salt(size=32):
> >>>   return secrets.token_bytes(size)
> >>>
> >>> def der_key(salt, password):
> >>>   kdf = Scrypt(salt=salt, length=32, n=2**20, r=8, p=1)
> >>>   return kdf.derive(password.encode())
> >>>
> >>> def gen_symmkey(salt, password):
> >>>   symmkey = der_key(salt, password)
> >>>   return symmkey
> >>>   #return base64.urlsafe_b64encode(symmkey)
> >>>
> >>> def encrypt(nonce, fname, aesgcmsiv):
> >>>   with open(fname, "rb") as infile:
> >>>     file_data = infile.read()
> >>>
> >>>   # encrypt data
> >>>   edata = aesgcmsiv.encrypt(nonce, file_data, aad)
> >>>   with open(fname, "wb") as outfile:
> >>>      outfile.write(edata)
> >>>
> >>>
> >>> def decrypt(nonce, fname, aesgcmsiv):
> >>>   with open(fname, "rb") as infile:
> >>>     edata = infile.read()
> >>>
> >>>   try:
> >>>     data = aesgcmsiv.decrypt(nonce, edata, aad)
> >>>   except cryptography.exceptions.InvalidTag:
> >>>     print("something went wrong")
> >>>     return False
> >>>
> >>>   with open(fname, "wb") as outfile:
> >>>      outfile.write(data)
> >>>
> >>> def call_crypto(saltsize, password):
> >>>    if os.path.isfile(saltfile):
> >>>      salt = open(saltfile, 'rb').read()
> >>>    else:
> >>>      salt = gen_salt(saltsize)
> >>>      with open(saltfile, 'wb') as sfile:
> >>>         sfile.write(salt)
> >>>
> >>>    key = gen_symmkey(salt, password)
> >>>    aesgcmsiv = AESGCMSIV(key)
> >>>
> >>>    #print('key is: ', key)
> >>>
> >>>    # dir walk and store files to process in a list
> >>>    lsdir(rootpath)
> >>>
> >>>    # encrypt/decrypt all elements in the 'files' list
> >>>    if ENC:
> >>>      for file in files:
> >>>        nonce = os.urandom(12)
> >>>        encrypt(nonce, file, aesgcmsiv)
> >>>        nfile = "/tmp/cstore/csrs/eud1.red.ftf.net.csr.nonce"
> >>>        with open(nfile, 'wb') as f:
> >>>          f.write(nonce)
> >>>    else:
> >>>        for file in files:
> >>>          #nfile = Path.joinpath(file, ".nonce")
> >>>          nfile = "/tmp/cstore/csrs/eud1.red.ftf.net.csr.nonce"
> >>>          with open(nfile, 'rb') as f:
> >>>            nonce = f.read()
> >>>            decrypt(nonce, file, aesgcmsiv)
> >>>
> >>> if __name__ == "__main__":
> >>>
> >>>    password = some_password
> >>>
> >>>    ENC = False
> >>>    call_crypto(saltsize, password)
> >>>
> >>>
> >>> Best,
> >>> PE
> >>>
> >>> On Sat, Jan 4, 2025 at 1:25 PM Alex Gaynor <alex.gay...@gmail.com>
> wrote:
> >>>>
> >>>> It's impossible to say without seeing your code. If
> >>>> encrypt()/decrypt() isn't working, then some of your parameters don't
> >>>> match between them.
> >>>>
> >>>> Alex
> >>>>
> >>>> On Sat, Jan 4, 2025 at 4:11 PM Sriram R <sramac...@gmail.com> wrote:
> >>>> >
> >>>> > Also, I'm saving and reading the ct and the nonce values in binary
> mode during encryption and decryption. Not sure if that needs to be done
> using a codec if the read/write operation is damaging the values.
> >>>> >
> >>>> > Appreciate taking the time to respond to this issue.
> >>>> >
> >>>> >
> >>>> > On Sat, Jan 4, 2025, 12:52 PM Sriram R <sramac...@gmail.com> wrote:
> >>>> >>
> >>>> >> Yes, all the other kdf parameters are the same. Like the salt
> size, n, p, r values etc.
> >>>> >> Any ideas as to why the decryption fails?
> >>>> >> I'm passing the same nonce to the .decrypt() method.
> >>>> >>
> >>>> >>
> >>>> >> On Sat, Jan 4, 2025, 12:46 PM Alex Gaynor <alex.gay...@gmail.com>
> wrote:
> >>>> >>>
> >>>> >>> Assuming the salt, and all other parameters passed to the KDF are
> the
> >>>> >>> same, then yes.
> >>>> >>>
> >>>> >>> On Sat, Jan 4, 2025 at 3:34 PM Sriram R <sramac...@gmail.com>
> wrote:
> >>>> >>> >
> >>>> >>> > Appreciate the symmetric key explanation. If the key is derived
> using a password based kdf during encryption, isn't it reasonable to expect
> the same key would be generated by the kdf during decryption phase if the
> password
> >>>> >>> > is also the same?
> >>>> >>> >
> >>>> >>> > PE
> >>>> >>> >
> >>>> >>> >
> >>>> >>> > On Sat, Jan 4, 2025, 9:30 AM Alex Gaynor <alex.gay...@gmail.com>
> wrote:
> >>>> >>> >>
> >>>> >>> >> Based on "it creates a new key from the password and is used
> for
> >>>> >>> >> decryption" it sounds like you're using different keys for
> encryption
> >>>> >>> >> and decryption.
> >>>> >>> >>
> >>>> >>> >> You need to use the same key to decrypt a value as you used to
> encrypt
> >>>> >>> >> it -- this is the point of symmetric encryption! It wouldn't
> make much
> >>>> >>> >> sense if you could decrypt a value without possessing the key.
> >>>> >>> >>
> >>>> >>> >> How exactly you manage your keys depends a lot on your
> application,
> >>>> >>> >> deployment environment, and threat model, so I can't really
> provide
> >>>> >>> >> any general purpose advice. You generally should not store the
> key
> >>>> >>> >> with the ciphretext, as there's basically no threat model that
> makes
> >>>> >>> >> sense under.
> >>>> >>> >>
> >>>> >>> >> Alex
> >>>> >>> >>
> >>>> >>> >> On Sat, Jan 4, 2025 at 12:28 PM Sriram R via Cryptography-dev
> >>>> >>> >> <cryptography-dev@python.org> wrote:
> >>>> >>> >> >
> >>>> >>> >> > Hello,
> >>>> >>> >> >
> >>>> >>> >> > I'm reaching out to the cryptography experts for this issue.
> >>>> >>> >> >
> >>>> >>> >> > Using Python 3.9 on a RHEL 9.4 platform with the
> cryptography module installed on it.
> >>>> >>> >> > The requirements are to encrypt some data using
> classcryptography.hazmat.primitives.ciphers.aead.AESGCM(key)
> >>>> >>> >> >
> >>>> >>> >> > I've written the encryption code to use the above cipher and
> it works without any issues.
> >>>> >>> >> >
> >>>> >>> >> > The issue I'm running into is in the decryption step. The
> same Python code is called with the flag set to decryption but it raises
> the InvalidToken exception.
> >>>> >>> >> > Reading the documentation it says this could occur if the
> ciphertext is changed, which it is not. Or if the nonce is different, I
> adjusted the code to save each nonce during the encryption process and I
> supply this same nonce during decryption.
> >>>> >>> >> > The documentation also says this exception can occur if the
> key is different.
> >>>> >>> >> >
> >>>> >>> >> > This is where my confusion is, the .decrypt() only takes in
> the ct, nonce and aad parameters.
> >>>> >>> >> > Obviously when the Python module is run for decryption, it
> creates a new key from the password and is used for decryption. Which will
> be different than what was used during encryption.
> >>>> >>> >> > I don't think the solution is to also store the key along
> with the nonce, since it's a very bad security practice.
> >>>> >>> >> >
> >>>> >>> >> > What am I missing?
> >>>> >>> >> > Do I need to parse the ciphertext and extract the tag or
> something? But then .decrypt() method doesn't use a tag parameter.
> >>>> >>> >> >
> >>>> >>> >> > FYI, I'm saving the ciphertext and the nonce with the 'wb'
> flag in the open() statement and the decryption step uses the 'rb' flag to
> read in the ciphertext and the nonce.
> >>>> >>> >> >
> >>>> >>> >> > The example code snippet in the cryptography website shows
> the encrypt and decrypt operation in sequence.
> >>>> >>> >> > In my situation, encryption happens at one time and the
> decryption has to happen some time later.
> >>>> >>> >> >
> >>>> >>> >> > Several websites/users are using the Pycryptodome module for
> this.
> >>>> >>> >> > I'd rather not because the cryptography module works great
> for my other requirements.
> >>>> >>> >> > Also I'd prefer not to use cryptography module and the
> Pycryptodome module as well. I think that would be overkill.
> >>>> >>> >> >
> >>>> >>> >> > Best
> >>>> >>> >> > PE
> >>>> >>> >> > _______________________________________________
> >>>> >>> >> > Cryptography-dev mailing list
> >>>> >>> >> > Cryptography-dev@python.org
> >>>> >>> >> > https://mail.python.org/mailman/listinfo/cryptography-dev
> >>>> >>> >>
> >>>> >>> >>
> >>>> >>> >>
> >>>> >>> >> --
> >>>> >>> >> All that is necessary for evil to succeed is for good people
> to do nothing.
> >>>> >>>
> >>>> >>>
> >>>> >>>
> >>>> >>> --
> >>>> >>> All that is necessary for evil to succeed is for good people to
> do nothing.
> >>>>
> >>>>
> >>>>
> >>>> --
> >>>> All that is necessary for evil to succeed is for good people to do
> nothing.
>
>
>
> --
> All that is necessary for evil to succeed is for good people to do nothing.
>
_______________________________________________
Cryptography-dev mailing list
Cryptography-dev@python.org
https://mail.python.org/mailman/listinfo/cryptography-dev

Reply via email to