Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pyage fails to decrypt one of the official AGE test vectors #13

Closed
marekyggdrasil opened this issue Apr 2, 2024 · 2 comments
Closed

Comments

@marekyggdrasil
Copy link

marekyggdrasil commented Apr 2, 2024

Hello! I was playing with your library and found a problem. Not sure if I am using it incorrectly or if there is a bug.

from age.file import Decryptor as ageStreamDecrypt
from age.keys.agekey import AgePrivateKey

from io import BytesIO

# official AGE test vector
# https://github.com/C2SP/CCTV/blob/3ec4d716e80597545ed285cf62af3dded3a14f65/age/testdata/x25519

expected_payload = '013f54400c82da08037759ada907a8b864e97de81c088a182062c4b5622fd2ab'
file_key = '59454c4c4f57205355424d4152494e45'
identity = 'AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6'

age_payload = 'age-encryption.org/v1\n-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc\nEmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U\n--- Vn+54jqiiUCE+WZcEVY3f1sqHjlu/z1LCQ/T7Xm7qI0\nîÏbÇΑ´3\'NhÔòù�L·L[þ÷¾ªRÈð¼�™,�ƒ1ûf'.encode('utf-8')

keys = [AgePrivateKey.from_private_string(identity)]

buffer_in = BytesIO()
buffer_in.write(age_payload)
buffer_in.seek(0)

# prepare the output buffer and decrypt
buffer_out = BytesIO()
with ageStreamDecrypt(keys, buffer_in) as decryptor:
    buffer_out.write(decryptor.read())

# return the content of the output buffer
buffer_out.seek(0)
decrypted = buffer_out.read()
print(decrypted)

fails with

Traceback (most recent call last):
  File "/Users/marek/Development/open-source/demonstrate-hmac-problem/page.py", line 23, in <module>
    with ageStreamDecrypt(keys, buffer_in) as decryptor:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/marek/.pyenv/versions/mimblewimble/lib/python3.11/site-packages/age/file.py", line 78, in __init__
    self._decrypt_body()
  File "/Users/marek/.pyenv/versions/mimblewimble/lib/python3.11/site-packages/age/file.py", line 129, in _decrypt_body
    plaintext = stream_decrypt(stream_key, ciphertext)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/marek/.pyenv/versions/mimblewimble/lib/python3.11/site-packages/age/stream.py", line 48, in stream_decrypt
    decrypted += aead.decrypt(nonce=packed_nonce, data=block, associated_data=None)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cryptography.exceptions.InvalidTag

the test vector is

expect: success
payload: 013f54400c82da08037759ada907a8b864e97de81c088a182062c4b5622fd2ab
file key: 59454c4c4f57205355424d4152494e45
identity: AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6

age-encryption.org/v1
-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc
EmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U
--- Vn+54jqiiUCE+WZcEVY3f1sqHjlu/z1LCQ/T7Xm7qI0
îÏbÇΑ´3'NhÔòù�L·L[þ÷¾ªRÈð¼�™,�ƒ1ûf

ref https://github.com/C2SP/CCTV/blob/3ec4d716e80597545ed285cf62af3dded3a14f65/age/testdata/x25519

many thanks in advance for your comments!

@marekyggdrasil
Copy link
Author

I found the payload is not valid. I examined the test vector using a hex editor and I found the bytes of the payload should be eecf62c7ce91b433274e68d4f2f9134cb74c5bfef7beaa52c8f0bc0e992c1e8331fb66.

from age.file import Decryptor as ageStreamDecrypt
from age.keys.agekey import AgePrivateKey

from io import BytesIO

# official AGE test vector
# https://github.com/C2SP/CCTV/blob/3ec4d716e80597545ed285cf62af3dded3a14f65/age/testdata/x25519

expected_payload = '013f54400c82da08037759ada907a8b864e97de81c088a182062c4b5622fd2ab'
file_key = '59454c4c4f57205355424d4152494e45'
identity = 'AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6'

age_payload = 'age-encryption.org/v1\n-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc\nEmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U\n--- Vn+54jqiiUCE+WZcEVY3f1sqHjlu/z1LCQ/T7Xm7qI0\n'.encode('utf-8') + bytes.fromhex('eecf62c7ce91b433274e68d4f2f9134cb74c5bfef7beaa52c8f0bc0e992c1e8331fb66')

keys = [AgePrivateKey.from_private_string(identity)]

buffer_in = BytesIO()
buffer_in.write(age_payload)
buffer_in.seek(0)

# prepare the output buffer and decrypt
buffer_out = BytesIO()
with ageStreamDecrypt(keys, buffer_in) as decryptor:
    buffer_out.write(decryptor.read())

# return the content of the output buffer
buffer_out.seek(0)
decrypted = buffer_out.read()

print()
print('decrypted payload is')
print(decrypted)

HMAC verification is passing and decrypted payload is age string. The script outputs

encoded mac Vn+54jqiiUCE+WZcEVY3f1sqHjlu/z1LCQ/T7Xm7qI0
mac 567fb9e23aa2894084f9665c1156377f5b2a1e396eff3d4b090fd3ed79bba88d
decrypted payload is
b'age'

I will probably ask if the testvector is correct, probably just payload entry is invalid.

@marekyggdrasil
Copy link
Author

Ok nevermind, I found SHA256(age)=013f54400c82da08037759ada907a8b864e97de81c088a182062c4b5622fd2ab, that makes sense and all is working now.

Thanks for great lib!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant