Skip to main content
Version: 7.0

Cryptographic algorithms

Passwork uses different cryptographic algorithms on the server and client.

Algorithms overview

PurposeAlgorithmWhere used
Key derivation from passwordPBKDF2Master key generation
Symmetric encryption (server)AES-256-CFBServer-side database encryption
Symmetric encryption (client)CryptoJS AES-256-CBCAll client data
Asymmetric encryptionRSA-OAEPKey exchange
HashingSHA-256, SHA-512Password verification, integrity
Random number generationWebCrypto APIKey generation, IV, salt

PBKDF2 (Password-Based Key Derivation Function 2)

PBKDF2 is used to derive a cryptographic key from the user's master password.

Client parameters

ParameterValue
AlgorithmPBKDF2
Hash functionSHA-256
Iterations300,000
Output key length512 bits
Salt20 characters, unique per user
Librarypbkdf2 (npm)

Server parameters

ParameterValue
AlgorithmPBKDF2
Hash functionSHA-512
Iterations600,000
Output key length512 bits
LibraryPHP hash_pbkdf2()
Parameter differences

SHA-256 with 300,000 iterations is used on the client for balance between security and browser performance. More stringent parameters (SHA-512, 600,000 iterations) are applied on the server for authentication password hashing.

Salt

ParameterValue
Length20 characters
AlphabetA-Z, a-z, 0-9, @, ! (64 characters)
Entropy~120 bits
GenerationServer, cryptographically secure
StorageServer, in user profile
UniquenessUnique per user
Server-side generation

Salt is always generated on the server and transmitted to the client. The client does not generate salt independently, ensuring use of a cryptographically secure generator.

Result format

PBKDF2 result on the client is encoded as a string:

pbkdf:sha256:300000:64:{salt}

Purpose of high iteration count

High iteration count (300,000+) significantly slows brute-force attacks:

  • Each attempt takes substantial time
  • Parallel GPU brute-forcing is hindered
  • Precomputed tables are impossible due to unique salt

Automatic hash migration

The system supports automatic migration of PBKDF2 hashes when parameters change.

Server hash format:

pbkdf:{base64_hash}:{algorithm}:{iterations}:{length}:{salt}

Example: pbkdf:Abc123...==:sha512:600000:64:xY3zKmN9qR2w...

Migration mechanism:

  1. User logs into the system
  2. System checks existing hash parameters
  3. If parameters differ from current settings → rehashing required
  4. Password is automatically hashed with new parameters
  5. New hash is saved to database

What can be updated:

ParameterCurrent valueExample new values
Hash algorithmSHA-512SHA3-512, BLAKE2b512
Iteration count600,0001,000,000, 2,000,000
Key length512 bits256, 1024 bits
Gradual migration

When parameters are updated:

  • New users → immediately get hashes with new parameters
  • Existing users → migration occurs on next login
  • Users without login → old hashes continue to work

Migration is transparent to users — they just enter their password as usual.


AES (Advanced Encryption Standard)

Passwork uses different AES modes on server and client.

Server encryption: AES-256-CFB

AES-256 in CFB (Cipher Feedback) mode via OpenSSL is used on the server.

ParameterValue
AlgorithmAES-256-CFB
Key length256 bits
Block size128 bits
Initialization Vector (IV)128 bits, random per encryption
LibraryOpenSSL (via PHP)

CFB mode characteristics:

  • Stream cipher mode
  • No padding required
  • IV stored with ciphertext

Usage: encrypting data in database (external links, settings, LDAP/SMTP passwords).

Server IV generation:

ParameterValue
Length128 bits
GeneratorCryptographically secure (OS CSPRNG)
UniquenessNew IV for each encryption operation
StorageAt the beginning of encrypted data

Encrypted data structure: [128 bit IV][ciphertext]

Client encryption: CryptoJS AES-256-CBC

CryptoJS library is used on the client for all symmetric encryption operations.

ParameterValue
LibraryCryptoJS
ModeCBC (Cipher Block Chaining)
Key length256 bits
PaddingPKCS#7
IVAutomatic (128 bits)
KDFBuilt-in key derivation function
Output encodingBase32

Key transformation to AES-256:

Symmetric keys in Passwork are 100 characters (~596 bits entropy), but AES-256 requires exactly 256-bit key. CryptoJS automatically performs transformation via key derivation function (KDF):

  1. Random 64-bit salt is generated
  2. Original 100-character key is transformed to 256-bit AES key
  3. Salt is saved with ciphertext for decryption
Why redundant entropy?

Input 596 bits guarantee maximum strength of the 256-bit output key. This also ensures unification — all symmetric keys (vault, record, attachment) are generated identically.

Client IV generation:

CryptoJS automatically generates IV for each encryption:

ParameterValue
Length128 bits
Generatorwindow.crypto.getRandomValues()
UniquenessNew IV for each encryption operation
Storage formatIncluded in OpenSSL-compatible format

CryptoJS output format: "Salted__" + [64 bit salt] + [ciphertext with IV] → Base64

Why different modes?

CriterionServer (CFB)Client (CBC)
LibraryOpenSSLCryptoJS
Choice reasonPHP standardBackward compatibility
AdvantagesStream modeWide support

CryptoJS vs WebCrypto API

CryptoJS library is used for symmetric encryption on the client, not the native WebCrypto API. Here's a comparison.

Comparison:

AspectCryptoJSWebCrypto API
ImplementationPure JavaScriptNative browser code
PerformanceSlowerSignificantly faster
Timing attack protectionNo guaranteesImplementation-level protection
Memory managementKeys in JS heapKeys can be non-extractable
APISynchronousAsynchronous (Promise)
CompatibilityAny JS environmentModern browsers only

Why CryptoJS is used:

  1. Backward compatibility — existing encrypted data uses CryptoJS format
  2. Synchronous API — easier integration with existing codebase
  3. Universality — works in any JavaScript environment

Security measures in current implementation:

  • PBKDF2 via separate library — master key derived via cryptographically strong PBKDF2
  • WebCrypto for RSA — critical asymmetric operations performed via native API
  • Cryptographically secure IV generation — via crypto.getRandomValues(), not Math.random()
  • Data encrypted once — timing attacks require multiple operations with same key

Risk assessment:

ThreatRisk levelJustification
Timing attacksLowRequires local browser access
Memory exposureLowWith such access, easier to intercept password during input
Known CVEMinimalUsed CryptoJS version has no critical vulnerabilities
Future development

Future versions plan gradual transition to WebCrypto API for symmetric encryption. This will enable:

  • Using AES-GCM (authenticated encryption) instead of AES-CBC
  • 10-100x performance improvement
  • Browser-level key protection

Migration will be performed with backward compatibility for existing data.


RSA (Rivest–Shamir–Adleman)

RSA is used for asymmetric encryption — secure exchange of symmetric keys between users.

Parameters

ParameterValue
AlgorithmRSA-OAEP
Modulus length2048 bits
Public exponent65537 (0x010001)
Hash functionSHA-256
LibraryWebCrypto API (crypto.subtle)

Key generation

RSA keys are generated on the client using WebCrypto API:

crypto.subtle.generateKey({
name: 'RSA-OAEP',
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: 'SHA-256'
}, true, ['encrypt', 'decrypt'])

Storage formats

KeyFormatDescription
PublicSPKI (PEM)SubjectPublicKeyInfo
PrivatePKCS#8 (PEM)Encrypted with master key

Supported formats

The system supports key import in formats:

  • PKCS#1-----BEGIN RSA PRIVATE KEY-----
  • PKCS#8-----BEGIN PRIVATE KEY-----
  • SPKI-----BEGIN PUBLIC KEY-----
  • JWK — JSON Web Key (for conversion)

Backward compatibility

For legacy 1024-bit keys, JSEncrypt library fallback is used, as WebCrypto API doesn't support RSA-1024.

Why RSA-2048?

AspectDescription
SecurityEquivalent to 112 bits of symmetric encryption
PerformanceAcceptable speed in browser
CompatibilityWide support across all browsers

Hashing

SHA-256

ParameterValue
Hash length256 bits
Library (client)js-sha256
UsageMaster key hash, PBKDF2, RSA-OAEP

SHA-512

ParameterValue
Hash length512 bits
Library (client)js-sha512
Library (server)PHP hash()
UsageServer PBKDF2, server key hash, search indices

Random number generation

All cryptographic parameters are generated using cryptographically secure random number generators (CSPRNG).

Entropy sources

Server (PHP)

GeneratorEntropy sourceUsage
random_bytes()OS CSPRNGBinary data (keys, tokens)
random_int()OS CSPRNGCharacter strings (salts, codes)

OS entropy sources:

  • Linux: /dev/urandom, getrandom() syscall
  • Windows: CryptGenRandom() (CryptoAPI)
  • macOS: arc4random_buf()

Client (JavaScript)

GeneratorEntropy sourceUsage
window.crypto.getRandomValues()Browser/OS CSPRNGNumbers, arrays
CryptoJS.lib.WordArray.random()crypto.getRandomValues()IV for AES

Browser entropy sources:

  • Chromium/Electron: BoringSSL CSPRNG
  • Firefox: NSS (Network Security Services)
  • Safari: CommonCrypto (Apple)

Cryptographic strength guarantees

PropertyGuarantee
UnpredictabilityImpossible to predict next value
Uniform distributionAll values equally probable
UnbiasedRejection sampling used
AvailabilityGenerators don't block

Generated keys and tokens

What is generatedLengthAlphabetEntropy
Symmetric keys
Vault key100 charactersA-Z, a-z, 0-9, @, !~596 bits
Record key100 charactersA-Z, a-z, 0-9, @, !~596 bits
Attachment key100 charactersA-Z, a-z, 0-9, @, !~596 bits
Link key100 characters → 256 bitsA-Z, a-z, 0-9, @, !~596 bits input
Server encryption key256 bitsBinary256 bits
Salts
PBKDF2 salt20 charactersA-Z, a-z, 0-9, @, !~120 bits
Vault salt32 charactersA-Z, a-z, 0-9, @, !~190 bits
Tokens and secrets
Secret Code (localStorage)100 charactersA-Z, a-z, 0-9~596 bits
Extension Secret60 charactersA-Z, a-z, 0-9~357 bits
Auth Token (extension)400 bitsHex400 bits
External link token43 charactersA-Z, a-z, 0-9~256 bits
Session tokens
Access Token256 bitsBase64256 bits
Refresh Token256 bitsBase64256 bits
Initialization vectors
IV (server, AES-CFB)128 bitsBinary128 bits
IV (client, AES-CBC)128 bitsBinary128 bits

Token uniqueness verification

For tokens requiring guaranteed uniqueness (link tokens, invite codes), database verification is performed:

  1. Random token is generated
  2. Uniqueness is checked in database
  3. On collision — regenerate
  4. Guaranteed unique token is returned

Collision probability:

  • 43 characters from 62: ~10^77 combinations
  • With billion tokens: collision probability ≈ 10^-59
  • Practically impossible

Cryptographic libraries

Client (JavaScript/TypeScript)

LibraryPurpose
WebCrypto APIRSA operations, random numbers
CryptoJSAES encryption (all data)
js-sha256SHA-256 hashing
js-sha512SHA-512 hashing
pbkdf2PBKDF2 key derivation
node-jsencryptRSA fallback (1024-bit)
pem-jwkPEM ↔ JWK conversion
totp-generatorTOTP code generation

Server (PHP)

ComponentPurpose
OpenSSLAES-256-CFB encryption
hash()SHA-256, SHA-512 hashing
hash_pbkdf2()PBKDF2 key derivation
random_bytes()Random data generation

Comparison with industry standards

ParameterPassworkNIST recommendations (2024)Status
Symmetric encryptionAES-256AES-128/192/256
Asymmetric encryptionRSA-2048RSA-2048+
HashingSHA-256/512SHA-2 family
PBKDF2 iterations300K/600K≥310K (SHA-256)
Random number generatorCSPRNGCSPRNG