Skip to content

Conversation

@StarHack
Copy link

@StarHack StarHack commented Nov 15, 2025

@tomgross

I managed to reverse engineer some parts of the decryption process:

  • Private Key
  • Public Key
  • File Names
  • Decrypt + Download Encrypted Files

For this backend I was not able to reverse the file content decryption process yet, unfortunately.

Usage:

>>> from pcloud import PyCloud
>>> pc = PyCloud('email@example.com', 'SecretPassword', crypto_password='your_crypto_password')
>>> pc.listfolder(folderid=123) # use an actual crypto folder id here

As for file contents, a bit more work is needed:

Crypto password → derives master key pair
       ↓
Encrypts CEK (Content Encryption Key for that file)
       ↓
CEK encrypts the file content

Encrypted CEK may be retrieved with https://[e]api.pcloud.com/getfilelink?fileid=...&getkey=1&auth=...

@tomgross
Copy link
Owner

Hi @StarHack, thanks for your contribution! It generally looks promising :-). Can you please make sure tests and pipeline passes.

@StarHack
Copy link
Author

@tomgross Got encrypted file downloads working now in my prototype written in Go. Will port it over to this python solution once ready.

And yes, I'll take a look at the test cases as well.

@StarHack
Copy link
Author

@tomgross
Sorry. It took me a bit longer than anticipated but decrypting file contents should now work properly as well. A little cryptography, yet no rocket science. ¯\_(ツ)_/¯

As mentioned before, I reverse engineered the entire crypto as it's unfortunately not open source; this is my current understanding of the architecture.

Overview

┌─────────────────────────────────────────────────────────┐
│                    Upload (Encrypt)                     │
└─────────────────────────────────────────────────────────┘
                         
Plain File → AES Encrypt (with CEK) → Upload to pCloud
                    ↑
                File CEK ← RSA Encrypt → Stored with file metadata


┌─────────────────────────────────────────────────────────┐
│                  Download (Decrypt)                     │
└─────────────────────────────────────────────────────────┘

Download from pCloud → AES Decrypt (with CEK) → Plain File
                              ↑
           File CEK ← RSA Decrypt ← Fetch via API
                    ↑
              RSA Private Key ← Derived from Crypto Password

Decrypting Files

When downloading an encrypted file:

  1. Fetch encrypted CEK:

    # API call: getfilelink?fileid=...&getkey=1
    response = api.getfilelink(fileid=xxx, getkey=1)
    encrypted_cek = response['key']
  2. Decrypt CEK with RSA:

    cek = rsa_private_key.decrypt(encrypted_cek)  # OAEP-SHA1
    # Now we have: aes_key (32 bytes) + hmac_key (64 bytes)
  3. Download encrypted file data:

    encrypted_data = pc.getzip(fileids=[fileid])
  4. Decrypt sectors:

    • Verify HMAC for each sector (integrity check)
    • Decrypt each 4KB sector with AES-256-CBC
    • Reassemble into original file

Encrypting Files (not implemented)

When uploading a file to an encrypted folder:

  1. Generate random CEK (Content Encryption Key):

    • 32 bytes for AES-256
    • 64 bytes for HMAC-SHA512
    • Total: 96 bytes of random data
  2. Encrypt file data (sector-based):

    • File split into 4KB sectors
    • Each sector encrypted with AES-256-CBC
    • Each sector authenticated with HMAC
    • Metadata tree structure for integrity (explained below)
  3. Encrypt the CEK:

    • CEK encrypted with your RSA public key (OAEP padding, SHA-1)
    • Encrypted CEK stored in file metadata
    • Even pCloud can't read it (they don't have your private key)
  4. Encrypt the filename:

    • Filename encrypted with folder's CEK
    • Uses AES-ECB or AES-CBC depending on length
    • Base32-encoded to be filesystem-safe

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

Successfully merging this pull request may close these issues.

2 participants