{"activeVersionTag":"latest","latestAvailableVersionTag":"latest","collection":{"info":{"_postman_id":"f551ee5c-3ee2-4685-a5d3-c63e2532180a","name":"Velvpay","description":"# **VelvPay API Packages**\n\nWelcome to the VelvPay ecosystem! VelvPay is designed to empower businesses across Africa by providing seamless, secure, and scalable payment solutions. To further enhance our API's functionality and to meet the diverse needs of businesses, here are suites of packages that extend the capabilities of the VelvPay API, making it easier for developers to integrate, manage, and innovate.\n\n### Join Our Developer Community\n\nAt VelvPay, we believe in the power of collaboration and open-source contributions. We're constantly looking for innovative developers who are passionate about building solutions that can make a real impact. If you've developed a package or an extension that can enhance the VelvPay API, we encourage you to share your work with our community.\n\nWhether you're refining existing packages or creating entirely new ones, your contributions are invaluable. By sharing your packages with us at [<b>hello@velvpay.com</b>](https://mailto:hello@velvpay.com), you'll be helping to create a richer, more diverse ecosystem that benefits all users of VelvPay.\n\nTogether, we can push the boundaries of what's possible and continue to unlock prosperity for businesses across Africa. We look forward to seeing what you create!\n\n---\n\n## **PACKAGES**\n\n## **PHP**\n\n### VELVPAY-PHP\n\n###### **CONTRIBUTOR**:\n\n- [TIM OLADOYINBO](https://github.com/timoladoyinbo)\n    \n\n###### **RESOURCE LINK:**\n\n- [https://github.com/digikraaft/velvpay-php](https://github.com/digikraaft/velvpay-php)\n    \n\n**JAVASCRIPT**\n\n###### **CONTRIBUTOR**:\n\n- [IFEDAYO OSUN](https://github.com/john-eleos)\n    \n\n###### **RESOURCE LINK:**\n\n- [https://www.npmjs.com/package/velv-js](https://www.npmjs.com/package/velv-js)\n    \n\n## **WORDPRESS**\n\n### VELVPAY-OFFICIAL\n\n###### CONTRIBUTOR:\n\n- [IFEDAYO OSUN](https://github.com/john-eleos)\n    \n\n###### RESOURCE LINK\n\n- [https://github.com/john-eleos/velvpay](https://github.com/john-eleos/velvpay)\n    \n\n# **VELVPAY API DOCUMENTATION**\n\n\\`amount\\` is in kobo with an alternative of \\`amountInNaira\\` which has its equivalent in naira, all amount to be send should be in kobo except otherwise specified by setting the `isNaira` flag to \\`true\\`.\n\n**GENERATE AN ENCRYPTED AUTHORIZATION TOKEN**\n\nvar SECRET_KEY = \"\";\n\nvar PUBLIC_KEY = \"\";  \nvar ENCYPTION_KEY =\"\";\n\nvar REFERENCE_ID = \"\"; // this should be unique for every request  \nvar AUTHORIZATION = SECRET_KEY+PUBLIC_KEY+REFERENCE_ID// please note that it needs to follow this order  \nvar AUTHORIZATION_TOKEN = CryptoJS.AES.encrypt(authorization,ENCYPTION_KEY).toString();\n\n# 🔐 VelvPay API – Authorization & Encryption Scheme\n\nTo ensure secure and verifiable communication with the VelvPay API, every request must include a dynamically generated, encrypted authorization token. This document outlines the structure, rules, and behavior of the encryption and header system.\n\n---\n\n## 📌 Overview\n\nEach API request must contain an **encrypted authorization token**, which is derived from a deterministic combination of keys and a unique reference ID using **\"AES Encryption\"**. This token is sent along with your public key and reference ID in the request headers.\n\n---\n\n## 🧬 Components Involved\n\n| Name | Description |\n| --- | --- |\n| `secretKey` | Your private credential used to authorize and verify requests. Keep this **confidential** at all times. |\n| `publicKey` | Your public identifier; shared with VelvPay to associate the request with your account. |\n| `encryptionKey` | A securely generated hex string used to encrypt the final authorization token. |\n| `referenceId` | A unique string per request, used to prevent replay attacks and ensure idempotency. |\n| `authorizationToken` | The encrypted string constructed from secretKey, publicKey, and referenceId. |\n\n---\n\n## 🔧 Token Generation Logic\n\n1. **Concatenate credentials in a specific order**:\n    \n\n``` bash\nauthorization = secretKey + publicKey + referenceId\n\n ```\n\n1. **Encrypt the** **`authorization`** **string** using your `encryptionKey`.\n    \n\nThis encryption must:\n\n- Be deterministic for the same input\n    \n- Produce a consistent ciphertext across implementations\n    \n- Use padding and a block cipher mode suitable for API compatibility\n    \n- Convert the final ciphertext to a string format appropriate for headers (e.g., Base64)\n    \n\n1. **Set this encrypted string as your token**:\n    \n\n```\nauthorizationToken = encrypt(authorization, encryptionKey)\n\n ```\n\n> 💡 The encryption function must support strong symmetric encryption using the provided `encryptionKey` (hex format). Ensure your implementation securely decodes and uses it as raw bytes. \n  \n\n---\n\n## 🔒 Reference ID Requirements\n\n- Must be **unique for each API request**\n    \n- Should follow a deterministic or UUID-based pattern\n    \n- Must be passed as part of the headers\n    \n- Can be reused only in **idempotent** request flows (like retries)\n    \n\n---\n\n## 🧾 Required Headers\n\nFor every authenticated request, the following headers **must** be set:\n\n| Header Key | Required | Description |\n| --- | --- | --- |\n| `api-key` | ✅ | The `authorizationToken` generated via encryption |\n| `public-key` | ✅ | The `publicKey` used in token composition |\n| `reference-id` | ✅ | The unique `referenceId` used for this request |\n| `idempotencykey` | ⚠️ _Conditional_ | Optional but required for POST requests that require idempotent behavior (e.g., creating a resource without duplication) |\n| `Content-Type` | ✅ | Must be `application/json` |\n\n---\n\n## ✅ Implementation Notes\n\n- The encryption key must be **securely generated** and **stored privately**.\n    \n- It is strongly recommended that:\n    \n- All inputs are **trimmed** and validated before encryption\n    \n- The same encryption logic is used consistently across environments\n    \n- The encryption library used **accepts hex-formatted keys** or decodes them correctly\n    \n- Cross-language compatibility depends on:\n    \n- Matching padding scheme (e.g., PKCS7)\n    \n- Matching cipher mode (e.g., CBC)\n    \n- Consistent handling of IVs (auto or fixed, based on implementation)\n    \n\n---\n\n## ⚠️ Security Considerations\n\n- Never log or expose your `secretKey` or `encryptionKey`\n    \n- Use HTTPS for all requests\n    \n- Regenerate `referenceId` for every new request to prevent replay attacks\n    \n- Do not reuse `authorizationToken` between requests\n    \n\n---\n\n## 🧪 Testing the Authorization Flow\n\nWhen testing via Postman or any third-party API client:\n\n1. Precompute the encrypted token using your encryption logic\n    \n2. Add all required headers as specified above\n    \n3. Confirm that the same logic used in your application code is used in your Postman pre-request scripts (especially for encryption)\n    \n\n---\n\n## 📤 Summary\n\nThe VelvPay API uses a layered authorization system based on dynamic encryption and signed identifiers. Always ensure:\n\n- Correct order: `secretKey + publicKey + referenceId`\n    \n- Consistent and secure encryption logic\n    \n- Inclusion of all required headers\n    \n- Unique `referenceId` per request\n    \n\n## 📬 Header Structure\n\nAll requests to the VelvPay API must include the following headers to ensure secure, encrypted communication.\n\n---\n\n### 🔹 GET Request Headers\n\nUse the following headers for **GET** requests:\n\n| Header Key | Required | Description |\n| --- | --- | --- |\n| `Content-Type` | ✅ | Must be `application/json` |\n| `api-key` | ✅ | Encrypted authorization token |\n| `public-key` | ✅ | Your `publicKey` used in token generation |\n| `reference-id` | ✅ | Unique request ID (used to prevent replay attacks) |\n\n---\n\n### 🔸 POST Request Headers\n\nUse the following headers for **POST** requests:\n\n| Header Key | Required | Description |\n| --- | --- | --- |\n| `Content-Type` | ✅ | Must be `application/json` |\n| `api-key` | ✅ | Encrypted authorization token |\n| `public-key` | ✅ | Your `publicKey` used in token generation |\n| `reference-id` | ✅ | Unique request ID (used to prevent replay attacks) |\n| `idempotencykey` | ⚠️ | Optional but recommended for safe retries (must be unique per POST request) |\n\n---\n\n> 🔐 Always ensure that the `api-key` value is freshly generated for each request, based on the correct combination:  \n`authorization = secretKey + publicKey + referenceId` \n  \n\n# VelvPay API Authentication Guide\n\n## Overview\n\nVelvPay uses AES-256-CBC encryption with OpenSSL's legacy key derivation (EVP_BytesToKey) to generate the api-key header. This guide provides a complete, language-agnostic walkthrough so you can implement it in any programming language.\n\n## Required Headers\n\n- api-key: Base64-encoded encrypted payload (secretKey+publicKey+referenceId)\n    \n- public-key: Your VelvPay public key\n    \n- reference-id: Unique transaction reference identifier\n    \n\n---\n\n## STEP-BY-STEP ENCRYPTION ALGORITHM\n\n### STEP 1: Prepare the Payload\n\nConcatenate three values in this exact order with NO separators:\n\npayload = secretKey + publicKey + referenceId\n\nExample:  \nsecretKey = \"sk_test_123\"  \npublicKey = \"pk_test_456\"  \nreferenceId = \"ref_789\"  \nResult: \"sk_test_123pk_test_456ref_789\"\n\n---\n\n### STEP 2: Generate Random Salt\n\nCreate 8 cryptographically secure random bytes:\n\nsalt = random_bytes(8)\n\nExample output: \\[0x5A, 0x3F, 0x8B, 0x12, 0xC4, 0x9E, 0x71, 0x2D\\]\n\nIMPORTANT: Salt MUST be random for each encryption. Never use a fixed salt.\n\n---\n\n### STEP 3: Derive Key and IV using EVP_BytesToKey\n\nThis is the CRITICAL step for CryptoJS/OpenSSL compatibility.\n\nAlgorithm:\n\n1. Convert encryption password to UTF-8 bytes\n    \n2. Concatenate: data = password_bytes + salt\n    \n3. Generate three MD5 hashes:\n    \n    - m\\[0\\] = MD5(data)\n        \n    - m\\[1\\] = MD5(m\\[0\\] + data)\n        \n    - m\\[2\\] = MD5(m\\[1\\] + data)\n        \n4. Derive key: key = m\\[0\\] + m\\[1\\] (32 bytes for AES-256)\n    \n5. Derive IV: iv = first 16 bytes of m\\[2\\]\n    \n\nDetailed Example:  \npassword = \"myEncryptionPassword\"  \nsalt = \\[0x5A, 0x3F, 0x8B, 0x12, 0xC4, 0x9E, 0x71, 0x2D\\]\n\npassword_bytes = UTF8(\"myEncryptionPassword\")  \ndata = password_bytes + salt\n\nm0 = MD5(data) // 16 bytes  \nm1 = MD5(m0 + data) // 16 bytes  \nm2 = MD5(m1 + data) // 16 bytes\n\nkey = m0 + m1 // 32 bytes total  \niv = m2\\[0:16\\] // First 16 bytes\n\nCRITICAL: Must use MD5, NOT SHA256 or any other hash function.\n\n---\n\n### STEP 4: Apply PKCS7 Padding\n\nAES requires input to be a multiple of 16 bytes. Add padding:\n\nAlgorithm:\n\n1. Calculate: padding_length = 16 - (data_length % 16)\n    \n2. Append padding_length bytes, each with value padding_length\n    \n\nExample 1:  \ndata = \"Hello\" (5 bytes)  \npadding_length = 16 - (5 % 16) = 11  \npadded = \"Hello\" + \\[0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B\\]  \nResult: 16 bytes total\n\nExample 2:  \ndata = \"1234567890123456\" (16 bytes, already aligned)  \npadding_length = 16 - (16 % 16) = 16  \npadded = data + \\[0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10\\]  \nResult: 32 bytes total\n\nNOTE: Some crypto libraries handle padding automatically. Check your library's documentation.\n\n---\n\n### STEP 5: Encrypt with AES-256-CBC\n\nEncrypt the padded payload using:\n\n- Algorithm: AES-256\n    \n- Mode: CBC (Cipher Block Chaining)\n    \n- Key: 32 bytes from Step 3\n    \n- IV: 16 bytes from Step 3\n    \n- Input: Padded payload from Step 4\n    \n\nPseudocode:  \ncipher = AES_256_CBC_init(key, iv)  \nciphertext = cipher.encrypt(padded_payload)\n\n---\n\n### STEP 6: Format as OpenSSL Salted Format\n\nCombine components in this EXACT order:\n\nresult = \"Salted__\" + salt + ciphertext\n\nBreakdown:\n\n1. Magic bytes: \"Salted__\" (8 ASCII bytes: 0x53 0x61 0x6C 0x74 0x65 0x64 0x5F 0x5F)\n    \n2. Salt: 8 random bytes from Step 2\n    \n3. Ciphertext: Encrypted data from Step 5\n    \n\nExample:  \nmagic = \\[0x53, 0x61, 0x6C, 0x74, 0x65, 0x64, 0x5F, 0x5F\\] // \"Salted__\"  \nsalt = \\[0x5A, 0x3F, 0x8B, 0x12, 0xC4, 0x9E, 0x71, 0x2D\\]  \nciphertext = \\[0x3A, 0x7F, ...\\] // encrypted bytes\n\nresult = magic + salt + ciphertext\n\n---\n\n### STEP 7: Base64 Encode\n\nConvert the entire binary result to Base64:\n\napi_key = Base64_encode(result)\n\nVERIFICATION: The output MUST start with \"U2FsdGVkX1\" (Base64 of \"Salted__\")\n\n---\n\n## COMPLETE PSEUDOCODE\n\nfunction generate_api_key(secret_key, public_key, reference_id, encryption_password):  \n// Step 1: Create payload  \npayload = secret_key + public_key + reference_id\n\n``` javascript\n// Step 2: Generate salt\nsalt = random_bytes(8)\n// Step 3: Derive key and IV using EVP_BytesToKey\npassword_bytes = UTF8_encode(encryption_password)\ndata = password_bytes + salt\nm0 = MD5(data)\nm1 = MD5(m0 + data)\nm2 = MD5(m1 + data)\nkey = m0 + m1  // 32 bytes\niv = m2[0:16]  // 16 bytes\n// Step 4: Pad payload (PKCS7)\npadding_length = 16 - (length(payload) % 16)\npadded_payload = payload + repeat(byte(padding_length), padding_length)\n// Step 5: Encrypt with AES-256-CBC\nciphertext = AES_256_CBC_encrypt(padded_payload, key, iv)\n// Step 6: Format as OpenSSL Salted format\nresult = bytes(\"Salted__\") + salt + ciphertext\n// Step 7: Base64 encode\napi_key = Base64_encode(result)\nreturn api_key\n\n ```\n\n---\n\n## IMPLEMENTATION CHECKLIST\n\n### Before You Start\n\n☐ Identify your language's crypto library (OpenSSL, native crypto, etc.)  \n☐ Verify it supports: AES-256-CBC, MD5, Base64, Random bytes  \n☐ Understand byte/string encoding in your language (UTF-8 vs ASCII)  \n☐ Check if PKCS7 padding is automatic or manual\n\n### During Implementation\n\n☐ Step 1: Concatenate strings correctly (no spaces, commas, or separators)  \n☐ Step 2: Generate cryptographically secure random bytes (not pseudo-random)  \n☐ Step 3: Implement EVP_BytesToKey with MD5 (NOT SHA256, NOT PBKDF2)  \n☐ Step 4: Apply PKCS7 padding correctly (or verify library does it)  \n☐ Step 5: Use AES-256-CBC mode with derived key and IV  \n☐ Step 6: Prepend \"Salted__\" magic bytes (8 bytes) + salt (8 bytes)  \n☐ Step 7: Base64 encode the ENTIRE binary result\n\n### Testing & Verification\n\n☐ Output starts with \"U2FsdGVkX1\" (always)  \n☐ Output length is typically 88-128 characters  \n☐ Each encryption produces DIFFERENT output (due to random salt)  \n☐ Same inputs with same password decrypt to same payload  \n☐ Test with multiple payload sizes  \n☐ Compare with reference implementations\n\n---\n\n## COMMON PITFALLS & SOLUTIONS\n\n### ❌ WRONG: Using PBKDF2 for key derivation\n\nkey = PBKDF2(password, salt, iterations=1000)\n\n✅ CORRECT: Use EVP_BytesToKey with MD5  \nm0 = MD5(password + salt)  \nm1 = MD5(m0 + password + salt)  \nm2 = MD5(m1 + password + salt)  \nkey = m0 + m1\n\nWHY: VelvPay uses OpenSSL's legacy EVP_BytesToKey, not modern PBKDF2.\n\n---\n\n### ❌ WRONG: Using SHA256 instead of MD5\n\nm0 = SHA256(data)\n\n✅ CORRECT: Use MD5  \nm0 = MD5(data)\n\nWHY: CryptoJS and OpenSSL legacy format use MD5 for key derivation.\n\n---\n\n### ❌ WRONG: Forgetting the \"Salted__\" prefix\n\nresult = salt + ciphertext\n\n✅ CORRECT: Include magic bytes  \nresult = \"Salted__\" + salt + ciphertext\n\nWHY: OpenSSL format requires the 8-byte magic prefix for identification.\n\n---\n\n### ❌ WRONG: Base64 encoding before combining\n\nresult = \"Salted__\" + salt + Base64(ciphertext)\n\n✅ CORRECT: Combine first, then encode  \nresult = Base64(\"Salted__\" + salt + ciphertext)\n\nWHY: Base64 must encode the entire binary result, not individual parts.\n\n---\n\n### ❌ WRONG: Using fixed or sequential salt\n\nsalt = \\[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\\]  \n// or  \nsalt = counter.to_bytes()\n\n✅ CORRECT: Use cryptographically secure random bytes  \nsalt = crypto_random_bytes(8)\n\nWHY: Predictable salts compromise security and make attacks easier.\n\n---\n\n### ❌ WRONG: Adding separators in payload\n\npayload = secret_key + \":\" + public_key + \":\" + reference_id\n\n✅ CORRECT: Direct concatenation  \npayload = secret_key + public_key + reference_id\n\nWHY: VelvPay expects direct concatenation with no delimiters.\n\n---\n\n## LANGUAGE-SPECIFIC GUIDANCE\n\n### JavaScript (Browser)\n\nLibrary: CryptoJS (simplest option)  \nCode:  \nconst payload = secretKey + publicKey + referenceId;  \nconst apiKey = CryptoJS.AES.encrypt(payload, encryptionPassword).toString();\n\nWatch out: CryptoJS handles everything automatically (EVP_BytesToKey, padding, format)\n\n---\n\n### Node.js\n\nLibrary: Native 'crypto' module  \nWatch out:\n\n- Must manually implement EVP_BytesToKey\n    \n- Use Buffer for byte operations\n    \n- String encoding matters (use 'utf8')\n    \n\n---\n\n### Python\n\nLibrary: pycryptodome or cryptography  \nWatch out:\n\n- Bytes vs strings (use .encode() and .decode())\n    \n- Must manually implement EVP_BytesToKey\n    \n- Import hashlib for MD5\n    \n\n---\n\n### PHP\n\nFunctions: openssl_encrypt(), md5(), base64_encode()  \nWatch out:\n\n- Use md5($data, true) for binary output (not hex)\n    \n- OPENSSL_RAW_DATA flag for raw ciphertext\n    \n- String concatenation with . operator\n    \n\n---\n\n### Java/Kotlin\n\nClasses: javax.crypto.Cipher, java.security.MessageDigest  \nWatch out:\n\n- Byte array handling and System.arraycopy()\n    \n- Charset encoding (StandardCharsets.UTF_8)\n    \n- Exception handling for crypto operations\n    \n\n---\n\n### Go\n\nPackages: crypto/aes, crypto/md5, encoding/base64  \nWatch out:\n\n- Explicit byte slicing and concatenation\n    \n- Use append() for combining byte slices\n    \n- Manual PKCS7 padding implementation\n    \n\n---\n\n### C#\n\nClasses: System.Security.Cryptography.Aes, MD5  \nWatch out:\n\n- LINQ for byte array operations (Concat, Take)\n    \n- Encoding.UTF8.GetBytes() for string conversion\n    \n- Using statements for proper disposal\n    \n\n---\n\n### Ruby\n\nLibrary: openssl (built-in)  \nWatch out:\n\n- String vs binary mode\n    \n- Use pack/unpack for byte operations\n    \n- Digest methods return binary by default\n    \n\n---\n\n### Rust\n\nCrates: aes, block-modes, md5, base64  \nWatch out:\n\n- Ownership and borrowing with byte arrays\n    \n- Use Vec for dynamic byte arrays\n    \n- Type conversions between &\\[u8\\] and Vec\n    \n\n---\n\n### Swift\n\nFramework: CommonCrypto  \nWatch out:\n\n- Bridging to C functions (CCCrypt, CC_MD5)\n    \n- Array for byte operations\n    \n- Data vs \\[UInt8\\] conversions\n    \n\n---\n\n### Bash/Shell\n\nCommand: openssl enc  \nCode:  \necho -n \"$payload\" | openssl enc -aes-256-cbc -md md5 -salt -pass pass:\"$password\" -base64\n\nWatch out: Use -md md5 flag for legacy key derivation\n\n---\n\n## TESTING YOUR IMPLEMENTATION\n\n### Test 1: Output Format Verification\n\napi_key = generate_api_key(\"secret\", \"public\", \"ref\", \"password\")  \nassert api_key.startsWith(\"U2FsdGVkX1\")\n\nExpected: PASS  \nIf FAIL: Check Step 6 (magic bytes) and Step 7 (Base64 encoding)\n\n---\n\n### Test 2: Randomness Check\n\nkey1 = generate_api_key(\"secret\", \"public\", \"ref\", \"password\")  \nkey2 = generate_api_key(\"secret\", \"public\", \"ref\", \"password\")  \nassert key1 != key2\n\nExpected: PASS (different due to random salt)  \nIf FAIL: Check Step 2 (salt generation must be random)\n\n---\n\n### Test 3: Length Validation\n\napi_key = generate_api_key(\"secret\", \"public\", \"ref\", \"password\")  \nassert length(api_key) >= 88 AND length(api_key) <= 128\n\nExpected: PASS  \nIf FAIL: Check for missing components or incorrect encoding\n\n---\n\n### Test 4: Decryption Verification (if available)\n\napi_key = generate_api_key(\"sk_test\", \"pk_test\", \"ref_123\", \"password\")  \ndecrypted = decrypt(api_key, \"password\")  \nassert decrypted == \"sk_testpk_testref_123\"\n\nExpected: PASS  \nIf FAIL: Check payload concatenation and encryption parameters\n\n---\n\n### Test 5: Cross-Language Compatibility\n\n// Generate in Language A  \napi_key_A = generate_api_key(\"secret\", \"public\", \"ref\", \"password\")\n\n// Decrypt in Language B  \ndecrypted_B = decrypt(api_key_A, \"password\")  \nassert decrypted_B == \"secretpublicref\"\n\nExpected: PASS  \nIf FAIL: Check EVP_BytesToKey implementation (most common issue)\n\n---\n\n## DEBUGGING GUIDE\n\n### Problem: Output doesn't start with \"U2FsdGVkX1\"\n\nPossible causes:\n\n1. Missing \"Salted__\" prefix in Step 6\n    \n2. Incorrect order of components (should be: magic + salt + ciphertext)\n    \n3. Base64 encoding applied to wrong data\n    \n\nSolution: Print intermediate values and verify binary structure before encoding\n\n---\n\n### Problem: Decryption fails\n\nPossible causes:\n\n1. Wrong key derivation (not using EVP_BytesToKey with MD5)\n    \n2. Incorrect IV extraction\n    \n3. Wrong AES mode (must be CBC, not ECB or GCM)\n    \n4. Padding issues\n    \n\nSolution: Compare your key and IV with a working implementation using same password and salt\n\n---\n\n### Problem: Different output length than expected\n\nPossible causes:\n\n1. Padding not applied or applied incorrectly\n    \n2. Missing salt or magic bytes\n    \n3. Partial Base64 encoding\n    \n\nSolution: Check that result = \"Salted__\" (8) + salt (8) + ciphertext (variable)\n\n---\n\n### Problem: Same output for different encryptions\n\nPossible causes:\n\n1. Salt is not random (fixed or sequential)\n    \n2. Using same salt value repeatedly\n    \n\nSolution: Verify random number generator is cryptographically secure\n\n---\n\n## EXAMPLE HTTP REQUEST\n\nGET [https://api.velvpay.com/test](https://api.velvpay.com/test) HTTP/1.1  \napi-key: U2FsdGVkX1+3xK8h9vN2pL7mQ8fR1sT4uV6wX7yZ8aB9cD0eF1gH2iJ3kL4mN5oP6qR7sT8uV9wX0yZ1aB2cD3eF4gH5iJ6kL7mN8oP9qR0sT1uV2wX3yZ4aB5cD6eF7gH8iJ9kL0mN1oP2qR3sT4uV5wX6yZ7aB8cD9eF0gH1iJ2kL3mN4oP5qR6sT7uV8wX9yZ0aB1cD2eF3gH4iJ5kL6mN7oP8qR9sT0uV1wX2yZ3aB4cD5eF6gH7iJ8kL9mN0oP1qR2sT3uV4wX5yZ6aB7cD8eF9gH0iJ1kL2mN3oP4qR5sT6uV7wX8yZ9aB0cD1eF2gH3iJ4kL5mN6oP7qR8sT9uV0wX1yZ2aB3cD4eF5gH6iJ7kL8mN9oP0qR1sT2uV3wX4yZ5aB6cD7eF8gH9iJ0kL1mN2oP3qR4sT5uV6wX7yZ8aB9cD0eF1gH2iJ3kL4mN5oP6qR7sT8uV9wX0yZ1aB2cD3eF4gH5iJ6kL7mN8oP9qR0sT1uV2wX3yZ4aB5cD6eF7gH8iJ9kL0mN1oP2qR3sT4uV5wX6yZ7aB8cD9eF0gH1iJ2kL3mN4oP5qR6sT7uV8wX9yZ0aB1cD2eF3gH4iJ5kL6mN7oP8qR9sT0uV1wX2yZ3aB4cD5eF6gH7iJ8kL9mN0oP1qR2sT3uV4wX5yZ6aB7cD8eF9gH0iJ1kL2mN3oP4qR5sT6uV7wX8yZ9aB0cD1eF2gH3iJ4kL5mN6oP7qR8sT9uV0wX1yZ2aB3cD4eF5gH6iJ7kL8mN9oP0qR1sT2uV3wX4yZ5aB6cD7eF8gH9iJ0kL1mN2oP3qR4sT5uV6wX7yZ8aB9cD0eF1gH2iJ3kL4mN5oP6qR7sT8uV9wX0yZ1aB2cD3eF4gH5iJ6kL7mN8oP9qR0sT1uV2wX3yZ4aB5cD6eF7gH8iJ9kL0mN1oP2qR3sT4uV5wX6yZ7aB8cD9eF0gH1iJ2kL3mN4oP5qR6sT7uV8wX9yZ0aB1cD2eF3gH4iJ5kL6mN7oP8qR9sT0uV1wX2yZ3aB4cD5eF6gH7iJ8kL9mN0oP1qR2sT3uV4wX5yZ6aB7cD8eF9gH0iJ1kL2mN3oP4qR5sT6uV7wX8yZ9aB0cD1eF2gH3iJ4kL5mN6oP7qR8sT9uV0wX1yZ2aB3cD4eF5gH6iJ7kL8mN9oP0qR1sT2uV3wX4yZ5aB6cD7eF8gH9iJ0kL1mN2oP3qR4sT5uV6wX7yZ8aB9cD0eF1gH2iJ3kL4mN5oP6qR7sT8uV9wX0yZ1aB2cD3eF4gH5iJ6kL7mN8oP9qR0sT1uV2wX3yZ4aB5cD6eF7gH8iJ9kL0mN1oP2qR3sT4uV5wX6yZ7aB8cD9eF0gH1iJ2kL3mN4oP5qR6sT7uV8wX9yZ0aB1cD2eF3gH4iJ5kL6mN7oP8qR9sT0uV1wX2yZ3aB4cD5eF6gH7iJ8kL9mN0oP1qR2sT3uV4wX5yZ6aB7cD8eF9gH0iJ1kL2mN3oP4qR5sT6uV7wX8yZ9aB0cD1eF2gH3iJ4kL5mN6oP7qR8sT9uV0wX1yZ2aB3cD4eF5gH6iJ7kL8mN9oP0qR1sT2uV3wX4yZ5aB6cD7eF8gH9iJ0kL1mN2oP3qR4sT5uV6wX7yZ8aB9cD0eF1gH2iJ3kL4mN5oP6qR7sT8uV9wX0yZ1aB2cD3eF4gH5iJ6kL7mN8oP9qR0sT1uV2wX3yZ4aB5cD6eF7gH8iJ9kL0mN1oP2qR3sT4uV5wX6yZ7aB8cD9eF0gH1iJ2kL3mN4oP5qR6sT7uV8wX9yZ0aB1cD2eF3gH4iJ5kL6mN7oP8qR9sT0uV1wX2yZ3aB4cD5eF6gH7iJ8kL9mN0oP1qR2sT3uV4wX5yZ6aB7cD8eF9gH0iJ1kL2mN3oP4qR5sT6uV7wX8yZ9aB0cD1eF2gH3iJ4kL5mN6oP7qR8sT9uV0wX1yZ2aB3cD4eF5gH6iJ7kL8mN9oP  \npublic-key: pk_live_abc123xyz789  \nreference-id: txn_20231210_001\n\n---\n\n## POSTMAN PRE-REQUEST SCRIPT\n\nAdd this to your request's Pre-request Script tab:\n\n// Get environment variables  \nconst secretKey = pm.environment.get('secret_key');  \nconst publicKey = pm.environment.get('public_key');  \nconst referenceId = pm.environment.get('reference_id');  \nconst encryptionPassword = pm.environment.get('encryption_password');\n\n// Validate all variables are set  \nif (!secretKey || !publicKey || !referenceId || !encryptionPassword) {  \nthrow new Error('Missing required environment variables');  \n}\n\n// Create payload  \nconst payload = secretKey + publicKey + referenceId;\n\n// Encrypt using CryptoJS (built into Postman)  \nconst apiKey = CryptoJS.AES.encrypt(payload, encryptionPassword).toString();\n\n// Set as environment variable  \npm.environment.set('api_key', apiKey);\n\n// Log for debugging  \nconsole.log('=== VelvPay API Key Generation ===');  \nconsole.log('Secret Key:', secretKey);  \nconsole.log('Public Key:', publicKey);  \nconsole.log('Reference ID:', referenceId);  \nconsole.log('Payload:', payload);  \nconsole.log('Generated API Key:', apiKey);  \nconsole.log('Starts with U2FsdGVkX1:', apiKey.startsWith('U2FsdGVkX1'));  \nconsole.log('API Key Length:', apiKey.length);\n\n---\n\n## ENVIRONMENT VARIABLES SETUP\n\nCreate a new environment in Postman and add these variables:\n\n| Variable Name | Initial Value | Current Value |\n| --- | --- | --- |\n| secret_key | sk_test_your_secret_key | sk_test_your_secret_key |\n| public_key | pk_test_your_public_key | pk_test_your_public_key |\n| reference_id | ref_unique_transaction_123 | ref_unique_transaction_123 |\n| encryption_password | your_encryption_password | your_encryption_password |\n| api_key | (leave empty) | (auto-generated) |\n\n---\n\n## QUICK VERIFICATION CHECKLIST\n\nAfter implementing, verify:  \n✓ api_key starts with \"U2FsdGVkX1\"  \n✓ api_key length is 88-128 characters  \n✓ Each request generates different api_key  \n✓ All three headers are present  \n✓ Payload concatenation has no separators  \n✓ Using MD5 for key derivation (not SHA256)  \n✓ Salt is random (not fixed)\n\n---\n\n## SUPPORT & TROUBLESHOOTING\n\nIf your implementation doesn't work:\n\n1. Enable debug logging - Print intermediate values (key, iv, salt, ciphertext)\n    \n2. Verify output format - Must start with \"U2FsdGVkX1\"\n    \n3. Check key derivation - Use MD5, not SHA256 or PBKDF2\n    \n4. Confirm concatenation - No spaces, commas, or separators in payload\n    \n5. Test with examples - Compare with working implementations\n    \n6. Cross-language test - Encrypt in one language, decrypt in another\n    \n\nCommon issues:\n\n- Wrong hash function (using SHA256 instead of MD5)\n    \n- Missing \"Salted__\" prefix\n    \n- Incorrect payload concatenation\n    \n- Fixed salt instead of random\n    \n- Base64 encoding applied to wrong data\n    \n\n---\n\n## REFERENCE IMPLEMENTATIONS\n\nSee the encryption examples below for complete working code in:\n\n# VelvPay API Key Generation - Code Examples\n\nComplete, copy-paste ready implementations for 20+ programming languages.\n\n---\n\n## 1\\. JavaScript (Browser - CryptoJS)\n\n``` html\n<comment class=&#x27;preserveHtml&#x27; class=&#x27;preserveHtml&#x27;> Include CryptoJS library  -->\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js\"></script>\n<script>\nfunction generateApiKey(secretKey, publicKey, referenceId, encryptionPassword) {\n    const payload = secretKey + publicKey + referenceId;\n    const apiKey = CryptoJS.AES.encrypt(payload, encryptionPassword).toString();\n    return apiKey;\n}\n// Usage\nconst secretKey = \"sk_test_your_secret_key\";\nconst publicKey = \"pk_test_your_public_key\";\nconst referenceId = \"ref_unique_123\";\nconst encryptionPassword = \"your_encryption_password\";\nconst apiKey = generateApiKey(secretKey, publicKey, referenceId, encryptionPassword);\nconsole.log(\"API Key:\", apiKey);\nconsole.log(\"Valid:\", apiKey.startsWith(\"U2FsdGVkX1\"));\n</script>\n\n ```\n\n---\n\n## 2\\. Node.js (Native Crypto)\n\n``` javascript\nconst crypto = require('crypto');\nfunction evpBytesToKey(password, salt, keyLen = 32, ivLen = 16) {\n    const md5 = (data) => crypto.createHash('md5').update(data).digest();\n    const data = Buffer.concat([Buffer.from(password, 'utf8'), salt]);\n    let d = md5(data);\n    let d1 = md5(Buffer.concat([d, data]));\n    let d2 = md5(Buffer.concat([d1, data]));\n    const key = Buffer.concat([d, d1]).slice(0, keyLen);\n    const iv = d2.slice(0, ivLen);\n    return { key, iv };\n}\nfunction encrypt(text, password) {\n    const salt = crypto.randomBytes(8);\n    const { key, iv } = evpBytesToKey(password, salt);\n    const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);\n    let encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]);\n    const result = Buffer.concat([\n        Buffer.from('Salted__', 'utf8'),\n        salt,\n        encrypted\n    ]);\n    return result.toString('base64');\n}\nfunction generateApiKey(secretKey, publicKey, referenceId, encryptionPassword) {\n    const payload = secretKey + publicKey + referenceId;\n    return encrypt(payload, encryptionPassword);\n}\n// Usage\nconst secretKey = \"sk_test_your_secret_key\";\nconst publicKey = \"pk_test_your_public_key\";\nconst referenceId = \"ref_unique_123\";\nconst encryptionPassword = \"your_encryption_password\";\nconst apiKey = generateApiKey(secretKey, publicKey, referenceId, encryptionPassword);\nconsole.log(\"API Key:\", apiKey);\nconsole.log(\"Valid:\", apiKey.startsWith(\"U2FsdGVkX1\"));\n\n ```\n\n---\n\n## 3\\. Python\n\n**Install:** `pip install pycryptodome`\n\n``` python\nfrom Crypto.Cipher import AES\nfrom Crypto.Random import get_random_bytes\nimport hashlib\nimport base64\ndef evp_bytes_to_key(password, salt, key_len=32, iv_len=16):\n    m = []\n    data = password.encode('utf-8') + salt\n    for i in range(3):\n        if i == 0:\n            m.append(hashlib.md5(data).digest())\n        else:\n            m.append(hashlib.md5(m[i-1] + data).digest())\n    key = b''.join(m[:2])[:key_len]\n    iv = m[2][:iv_len]\n    return key, iv\ndef pkcs7_pad(data, block_size=16):\n    pad_len = block_size - (len(data) % block_size)\n    return data + bytes([pad_len] * pad_len)\ndef encrypt(text, password):\n    salt = get_random_bytes(8)\n    key, iv = evp_bytes_to_key(password, salt)\n    cipher = AES.new(key, AES.MODE_CBC, iv)\n    padded_text = pkcs7_pad(text.encode('utf-8'))\n    encrypted = cipher.encrypt(padded_text)\n    result = b'Salted__' + salt + encrypted\n    return base64.b64encode(result).decode('utf-8')\ndef generate_api_key(secret_key, public_key, reference_id, encryption_password):\n    payload = secret_key + public_key + reference_id\n    return encrypt(payload, encryption_password)\n# Usage\nsecret_key = \"sk_test_your_secret_key\"\npublic_key = \"pk_test_your_public_key\"\nreference_id = \"ref_unique_123\"\nencryption_password = \"your_encryption_password\"\napi_key = generate_api_key(secret_key, public_key, reference_id, encryption_password)\nprint(f\"API Key: {api_key}\")\nprint(f\"Valid: {api_key.startswith('U2FsdGVkX1')}\")\n\n ```\n\n---\n\n## 4\\. PHP\n\n``` php\nfunction evpBytesToKey($password, $salt, $keyLen = 32, $ivLen = 16) {\n    $data = $password . $salt;\n    $m = [];\n    for ($i = 0; $i < 3; $i++) {\n        if ($i == 0) {\n            $m[] = md5($data, true);\n        } else {\n            $m[] = md5($m[$i-1] . $data, true);\n        }\n    }\n    $key = substr($m[0] . $m[1], 0, $keyLen);\n    $iv = substr($m[2], 0, $ivLen);\n    return [$key, $iv];\n}\nfunction encrypt($text, $password) {\n    $salt = openssl_random_pseudo_bytes(8);\n    list($key, $iv) = evpBytesToKey($password, $salt);\n    $encrypted = openssl_encrypt($text, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);\n    $result = 'Salted__' . $salt . $encrypted;\n    return base64_encode($result);\n}\nfunction generateApiKey($secretKey, $publicKey, $referenceId, $encryptionPassword) {\n    $payload = $secretKey . $publicKey . $referenceId;\n    return encrypt($payload, $encryptionPassword);\n}\n// Usage\n$secretKey = \"sk_test_your_secret_key\";\n$publicKey = \"pk_test_your_public_key\";\n$referenceId = \"ref_unique_123\";\n$encryptionPassword = \"your_encryption_password\";\n$apiKey = generateApiKey($secretKey, $publicKey, $referenceId, $encryptionPassword);\necho \"API Key: \" . $apiKey . \"\\n\";\necho \"Valid: \" . (strpos($apiKey, 'U2FsdGVkX1') === 0 ? 'true' : 'false') . \"\\n\";\n?>\n\n ```\n\n---\n\n## 5\\. Ruby\n\n``` ruby\nrequire 'openssl'\nrequire 'base64'\ndef evp_bytes_to_key(password, salt, key_len = 32, iv_len = 16)\n  data = password + salt\n  m = []\n  3.times do |i|\n    if i == 0\n      m << OpenSSL::Digest::MD5.digest(data)\n    else\n      m << OpenSSL::Digest::MD5.digest(m[i-1] + data)\n    end\n  end\n  key = (m[0] + m[1])[0, key_len]\n  iv = m[2][0, iv_len]\n  [key, iv]\nend\ndef encrypt(text, password)\n  salt = OpenSSL::Random.random_bytes(8)\n  key, iv = evp_bytes_to_key(password, salt)\n  cipher = OpenSSL::Cipher.new('aes-256-cbc')\n  cipher.encrypt\n  cipher.key = key\n  cipher.iv = iv\n  encrypted = cipher.update(text) + cipher.final\n  result = 'Salted__' + salt + encrypted\n  Base64.strict_encode64(result)\nend\ndef generate_api_key(secret_key, public_key, reference_id, encryption_password)\n  payload = secret_key + public_key + reference_id\n  encrypt(payload, encryption_password)\nend\n# Usage\nsecret_key = \"sk_test_your_secret_key\"\npublic_key = \"pk_test_your_public_key\"\nreference_id = \"ref_unique_123\"\nencryption_password = \"your_encryption_password\"\napi_key = generate_api_key(secret_key, public_key, reference_id, encryption_password)\nputs \"API Key: #{api_key}\"\nputs \"Valid: #{api_key.start_with?('U2FsdGVkX1')}\"\n\n ```\n\n---\n\n## 6\\. Java\n\n``` java\nimport javax.crypto.*;\nimport javax.crypto.spec.*;\nimport java.security.*;\nimport java.util.Base64;\nimport java.util.Arrays;\npublic class VelvPayEncryption {\n    private static byte[][] evpBytesToKey(byte[] password, byte[] salt) throws Exception {\n        MessageDigest md = MessageDigest.getInstance(\"MD5\");\n        byte[][] m = new byte[3][];\n        for (int i = 0; i < 3; i++) {\n            md.reset();\n            if (i > 0) md.update(m[i-1]);\n            md.update(password);\n            md.update(salt);\n            m[i] = md.digest();\n        }\n        byte[] key = new byte[32];\n        System.arraycopy(m[0], 0, key, 0, 16);\n        System.arraycopy(m[1], 0, key, 16, 16);\n        byte[] iv = Arrays.copyOf(m[2], 16);\n        return new byte[][] {key, iv};\n    }\n    public static String encrypt(String text, String password) throws Exception {\n        byte[] salt = new byte[8];\n        new SecureRandom().nextBytes(salt);\n        byte[][] keyIv = evpBytesToKey(password.getBytes(\"UTF-8\"), salt);\n        Cipher cipher = Cipher.getInstance(\"AES/CBC/PKCS5Padding\");\n        cipher.init(Cipher.ENCRYPT_MODE, \n                   new SecretKeySpec(keyIv[0], \"AES\"), \n                   new IvParameterSpec(keyIv[1]));\n        byte[] encrypted = cipher.doFinal(text.getBytes(\"UTF-8\"));\n        byte[] result = new byte[16 + encrypted.length];\n        System.arraycopy(\"Salted__\".getBytes(\"UTF-8\"), 0, result, 0, 8);\n        System.arraycopy(salt, 0, result, 8, 8);\n        System.arraycopy(encrypted, 0, result, 16, encrypted.length);\n        return Base64.getEncoder().encodeToString(result);\n    }\n    public static String generateApiKey(String secretKey, String publicKey, \n                                       String referenceId, String encryptionPassword) \n                                       throws Exception {\n        String payload = secretKey + publicKey + referenceId;\n        return encrypt(payload, encryptionPassword);\n    }\n    public static void main(String[] args) throws Exception {\n        String secretKey = \"sk_test_your_secret_key\";\n        String publicKey = \"pk_test_your_public_key\";\n        String referenceId = \"ref_unique_123\";\n        String encryptionPassword = \"your_encryption_password\";\n        String apiKey = generateApiKey(secretKey, publicKey, referenceId, encryptionPassword);\n        System.out.println(\"API Key: \" + apiKey);\n        System.out.println(\"Valid: \" + apiKey.startsWith(\"U2FsdGVkX1\"));\n    }\n}\n\n ```\n\n---\n\n## 7\\. Go\n\n``` go\npackage main\nimport (\n    \"crypto/aes\"\n    \"crypto/cipher\"\n    \"crypto/md5\"\n    \"crypto/rand\"\n    \"encoding/base64\"\n    \"fmt\"\n)\nfunc evpBytesToKey(password, salt []byte) ([]byte, []byte) {\n    var m [][]byte\n    data := append(password, salt...)\n    for i := 0; i < 3; i++ {\n        h := md5.New()\n        if i > 0 {\n            h.Write(m[i-1])\n        }\n        h.Write(data)\n        m = append(m, h.Sum(nil))\n    }\n    key := append(m[0], m[1]...)\n    iv := m[2]\n    return key, iv\n}\nfunc pkcs7Pad(data []byte, blockSize int) []byte {\n    padding := blockSize - (len(data) % blockSize)\n    padText := make([]byte, padding)\n    for i := range padText {\n        padText[i] = byte(padding)\n    }\n    return append(data, padText...)\n}\nfunc encrypt(text, password string) (string, error) {\n    salt := make([]byte, 8)\n    if _, err := rand.Read(salt); err != nil {\n        return \"\", err\n    }\n    key, iv := evpBytesToKey([]byte(password), salt)\n    block, err := aes.NewCipher(key)\n    if err != nil {\n        return \"\", err\n    }\n    plaintext := pkcs7Pad([]byte(text), aes.BlockSize)\n    ciphertext := make([]byte, len(plaintext))\n    mode := cipher.NewCBCEncrypter(block, iv)\n    mode.CryptBlocks(ciphertext, plaintext)\n    result := append([]byte(\"Salted__\"), append(salt, ciphertext...)...)\n    return base64.StdEncoding.EncodeToString(result), nil\n}\nfunc generateApiKey(secretKey, publicKey, referenceId, encryptionPassword string) (string, error) {\n    payload := secretKey + publicKey + referenceId\n    return encrypt(payload, encryptionPassword)\n}\nfunc main() {\n    secretKey := \"sk_test_your_secret_key\"\n    publicKey := \"pk_test_your_public_key\"\n    referenceId := \"ref_unique_123\"\n    encryptionPassword := \"your_encryption_password\"\n    apiKey, err := generateApiKey(secretKey, publicKey, referenceId, encryptionPassword)\n    if err != nil {\n        panic(err)\n    }\n    fmt.Println(\"API Key:\", apiKey)\n    fmt.Println(\"Valid:\", apiKey[:10] == \"U2FsdGVkX1\")\n}\n\n ```\n\n---\n\n## 8\\. C#\n\n``` csharp\nusing System;\nusing System.IO;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Text;\npublic class VelvPayEncryption\n{\n    private static (byte[], byte[]) EvpBytesToKey(byte[] password, byte[] salt)\n    {\n        using (var md5 = MD5.Create())\n        {\n            var m = new byte[3][];\n            var data = password.Concat(salt).ToArray();\n            for (int i = 0; i < 3; i++)\n            {\n                if (i == 0)\n                {\n                    m[i] = md5.ComputeHash(data);\n                }\n                else\n                {\n                    m[i] = md5.ComputeHash(m[i-1].Concat(data).ToArray());\n                }\n            }\n            var key = m[0].Concat(m[1]).ToArray();\n            var iv = m[2].Take(16).ToArray();\n            return (key, iv);\n        }\n    }\n    public static string Encrypt(string text, string password)\n    {\n        byte[] salt = new byte[8];\n        using (var rng = RandomNumberGenerator.Create())\n        {\n            rng.GetBytes(salt);\n        }\n        var (key, iv) = EvpBytesToKey(Encoding.UTF8.GetBytes(password), salt);\n        using (var aes = Aes.Create())\n        {\n            aes.Key = key;\n            aes.IV = iv;\n            aes.Mode = CipherMode.CBC;\n            aes.Padding = PaddingMode.PKCS7;\n            using (var encryptor = aes.CreateEncryptor())\n            {\n                byte[] encrypted = encryptor.TransformFinalBlock(\n                    Encoding.UTF8.GetBytes(text), 0, text.Length);\n                byte[] result = Encoding.UTF8.GetBytes(\"Salted__\")\n                    .Concat(salt)\n                    .Concat(encrypted)\n                    .ToArray();\n                return Convert.ToBase64String(result);\n            }\n        }\n    }\n    public static string GenerateApiKey(string secretKey, string publicKey, \n                                       string referenceId, string encryptionPassword)\n    {\n        string payload = secretKey + publicKey + referenceId;\n        return Encrypt(payload, encryptionPassword);\n    }\n    public static void Main()\n    {\n        string secretKey = \"sk_test_your_secret_key\";\n        string publicKey = \"pk_test_your_public_key\";\n        string referenceId = \"ref_unique_123\";\n        string encryptionPassword = \"your_encryption_password\";\n        string apiKey = GenerateApiKey(secretKey, publicKey, referenceId, encryptionPassword);\n        Console.WriteLine($\"API Key: {apiKey}\");\n        Console.WriteLine($\"Valid: {apiKey.StartsWith(\"U2FsdGVkX1\")}\");\n    }\n}\n\n ```\n\n---\n\n## 9\\. Kotlin\n\n``` kotlin\nimport javax.crypto.Cipher\nimport javax.crypto.spec.IvParameterSpec\nimport javax.crypto.spec.SecretKeySpec\nimport java.security.MessageDigest\nimport java.security.SecureRandom\nimport java.util.Base64\nfun evpBytesToKey(password: ByteArray, salt: ByteArray): Pair<ByteArray, ByteArray> {\n    val md = MessageDigest.getInstance(\"MD5\")\n    val m = mutableListOf<ByteArray>()\n    val data = password + salt\n    repeat(3) { i ->\n        md.reset()\n        if (i > 0) md.update(m[i-1])\n        md.update(data)\n        m.add(md.digest())\n    }\n    val key = m[0] + m[1]\n    val iv = m[2].take(16).toByteArray()\n    return Pair(key, iv)\n}\nfun encrypt(text: String, password: String): String {\n    val salt = ByteArray(8).apply { SecureRandom().nextBytes(this) }\n    val (key, iv) = evpBytesToKey(password.toByteArray(), salt)\n    val cipher = Cipher.getInstance(\"AES/CBC/PKCS5Padding\")\n    cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, \"AES\"), IvParameterSpec(iv))\n    val encrypted = cipher.doFinal(text.toByteArray())\n    val result = \"Salted__\".toByteArray() + salt + encrypted\n    return Base64.getEncoder().encodeToString(result)\n}\nfun generateApiKey(secretKey: String, publicKey: String, referenceId: String, \n                  encryptionPassword: String): String {\n    val payload = secretKey + publicKey + referenceId\n    return encrypt(payload, encryptionPassword)\n}\n// Usage\nfun main() {\n    val secretKey = \"sk_test_your_secret_key\"\n    val publicKey = \"pk_test_your_public_key\"\n    val referenceId = \"ref_unique_123\"\n    val encryptionPassword = \"your_encryption_password\"\n    val apiKey = generateApiKey(secretKey, publicKey, referenceId, encryptionPassword)\n    println(\"API Key: $apiKey\")\n    println(\"Valid: ${apiKey.startsWith(\"U2FsdGVkX1\")}\")\n}\n\n ```\n\n---\n\n## 10\\. Swift\n\n``` swift\nimport Foundation\nimport CommonCrypto\nfunc evpBytesToKey(password: String, salt: [UInt8]) -> ([UInt8], [UInt8]) {\n    var m: [[UInt8]] = []\n    let passwordBytes = Array(password.utf8)\n    let data = passwordBytes + salt\n    for i in 0..<3 {\n        var hash = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))\n        var input = i > 0 ? m[i-1] + data : data\n        CC_MD5(&input, CC_LONG(input.count), &hash)\n        m.append(hash)\n    }\n    let key = m[0] + m[1]\n    let iv = Array(m[2].prefix(16))\n    return (key, iv)\n}\nfunc encrypt(text: String, password: String) -> String? {\n    let salt = (0..<8).map { _ in UInt8.random(in: 0...255) }\n    let (key, iv) = evpBytesToKey(password: password, salt: salt)\n    guard let textData = text.data(using: .utf8) else { return nil }\n    let bufferSize = textData.count + kCCBlockSizeAES128\n    var buffer = [UInt8](repeating: 0, count: bufferSize)\n    var numBytesEncrypted = 0\n    let cryptStatus = CCCrypt(\n        CCOperation(kCCEncrypt),\n        CCAlgorithm(kCCAlgorithmAES),\n        CCOptions(kCCOptionPKCS7Padding),\n        key, key.count,\n        iv,\n        [UInt8](textData), textData.count,\n        &buffer, bufferSize,\n        &numBytesEncrypted\n    )\n    guard cryptStatus == kCCSuccess else { return nil }\n    let encrypted = Array(buffer.prefix(numBytesEncrypted))\n    let result = Array(\"Salted__\".utf8) + salt + encrypted\n    return Data(result).base64EncodedString()\n}\nfunc generateApiKey(secretKey: String, publicKey: String, referenceId: String, \n                   encryptionPassword: String) -> String? {\n    let payload = secretKey + publicKey + referenceId\n    return encrypt(text: payload, password: encryptionPassword)\n}\n// Usage\nlet secretKey = \"sk_test_your_secret_key\"\nlet publicKey = \"pk_test_your_public_key\"\nlet referenceId = \"ref_unique_123\"\nlet encryptionPassword = \"your_encryption_password\"\nif let apiKey = generateApiKey(secretKey: secretKey, publicKey: publicKey, \n                               referenceId: referenceId, \n                               encryptionPassword: encryptionPassword) {\n    print(\"API Key: \\(apiKey)\")\n    print(\"Valid: \\(apiKey.hasPrefix(\"U2FsdGVkX1\"))\")\n}\n\n ```\n\n---\n\n## 11\\. Rust\n\n**Cargo.toml dependencies:**\n\n``` toml\naes = \"0.8\"\nblock-modes = \"0.9\"\nmd5 = \"0.7\"\nrand = \"0.8\"\nbase64 = \"0.21\"\n\n ```\n\n``` rust\nuse aes::Aes256;\nuse block_modes::{BlockMode, Cbc};\nuse block_modes::block_padding::Pkcs7;\nuse md5::{Md5, Digest};\nuse rand::Rng;\nuse base64::{Engine as _, engine::general_purpose};\ntype Aes256Cbc = Cbc<Aes256, Pkcs7>;\nfn evp_bytes_to_key(password: &[u8], salt: &[u8]) -> (Vec<u8>, Vec<u8>) {\n    let mut m: Vec<Vec<u8>> = Vec::new();\n    let data: Vec<u8> = password.iter().chain(salt.iter()).copied().collect();\n    for i in 0..3 {\n        let mut hasher = Md5::new();\n        if i > 0 {\n            hasher.update(&m[i-1]);\n        }\n        hasher.update(&data);\n        m.push(hasher.finalize().to_vec());\n    }\n    let key: Vec<u8> = m[0].iter().chain(m[1].iter()).copied().collect();\n    let iv = m[2][..16].to_vec();\n    (key, iv)\n}\nfn encrypt(text: &str, password: &str) -> String {\n    let mut rng = rand::thread_rng();\n    let salt: Vec<u8> = (0..8).map(|_| rng.gen()).collect();\n    let (key, iv) = evp_bytes_to_key(password.as_bytes(), &salt);\n    let cipher = Aes256Cbc::new_from_slices(&key, &iv).unwrap();\n    let ciphertext = cipher.encrypt_vec(text.as_bytes());\n    let mut result = b\"Salted__\".to_vec();\n    result.extend_from_slice(&salt);\n    result.extend_from_slice(&ciphertext);\n    general_purpose::STANDARD.encode(&result)\n}\nfn generate_api_key(secret_key: &str, public_key: &str, reference_id: &str, \n                   encryption_password: &str) -> String {\n    let payload = format!(\"{}{}{}\", secret_key, public_key, reference_id);\n    encrypt(&payload, encryption_password)\n}\nfn main() {\n    let secret_key = \"sk_test_your_secret_key\";\n    let public_key = \"pk_test_your_public_key\";\n    let reference_id = \"ref_unique_123\";\n    let encryption_password = \"your_encryption_password\";\n    let api_key = generate_api_key(secret_key, public_key, reference_id, encryption_password);\n    println!(\"API Key: {}\", api_key);\n    println!(\"Valid: {}\", api_key.starts_with(\"U2FsdGVkX1\"));\n}\n\n ```\n\n---\n\n## 12\\. TypeScript\n\n**Install:** `npm install crypto-js @types/crypto-js`\n\n``` typescript\nimport CryptoJS from 'crypto-js';\nfunction generateApiKey(\n    secretKey: string, \n    publicKey: string, \n    referenceId: string, \n    encryptionPassword: string\n): string {\n    const payload = secretKey + publicKey + referenceId;\n    return CryptoJS.AES.encrypt(payload, encryptionPassword).toString();\n}\n// Usage\nconst secretKey: string = \"sk_test_your_secret_key\";\nconst publicKey: string = \"pk_test_your_public_key\";\nconst referenceId: string = \"ref_unique_123\";\nconst encryptionPassword: string = \"your_encryption_password\";\nconst apiKey: string = generateApiKey(secretKey, publicKey, referenceId, encryptionPassword);\nconsole.log(\"API Key:\", apiKey);\nconsole.log(\"Valid:\", apiKey.startsWith(\"U2FsdGVkX1\"));\n\n ```\n\n---\n\n## 13\\. Bash/Shell\n\n``` bash\n#!/bin/bash\ngenerate_api_key() {\n    local secret_key=\"$1\"\n    local public_key=\"$2\"\n    local reference_id=\"$3\"\n    local encryption_password=\"$4\"\n    local payload=\"${secret_key}${public_key}${reference_id}\"\n    # Using OpenSSL with MD5 key derivation (legacy)\n    echo -n \"$payload\" | openssl enc -aes-256-cbc -md md5 -salt \\\n        -pass pass:\"$encryption_password\" -base64\n}\n# Usage\nSECRET_KEY=\"sk_test_your_secret_key\"\nPUBLIC_KEY=\"pk_test_your_public_key\"\nREFERENCE_ID=\"ref_unique_123\"\nENCRYPTION_PASSWORD=\"your_encryption_password\"\nAPI_KEY=$(generate_api_key \"$SECRET_KEY\" \"$PUBLIC_KEY\" \"$REFERENCE_ID\" \"$ENCRYPTION_PASSWORD\")\necho \"API Key: $API_KEY\"\n\n ```\n\n---\n\n## 14\\. PowerShell\n\n``` powershell\nfunction Get-EVPBytesToKey {\n    param([byte[]]$Password, [byte[]]$Salt)\n    $md5 = [System.Security.Cryptography.MD5]::Create()\n    $m = @()\n    $data = $Password + $Salt\n    for ($i = 0; $i -lt 3; $i++) {\n        if ($i -eq 0) {\n            $m += ,$md5.ComputeHash($data)\n        } else {\n            $m += ,$md5.ComputeHash($m[$i-1] + $data)\n        }\n    }\n    $key = $m[0] + $m[1]\n    $iv = $m[2][0..15]\n    @{ Key = $key; IV = $iv }\n}\nfunction Encrypt-VelvPay {\n    param([string]$Text, [string]$Password)\n    $salt = New-Object byte[] 8\n    $rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()\n    $rng.GetBytes($salt)\n    $keyIv = Get-EVPBytesToKey -Password ([Text.Encoding]::UTF8.GetBytes($Password)) -Salt $salt\n    $aes = [System.Security.Cryptography.Aes]::Create()\n    $aes.Key = $keyIv.Key\n    $aes.IV = $keyIv.IV\n    $aes.Mode = [System.Security.Cryptography.CipherMode]::CBC\n    $aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7\n    $encryptor = $aes.CreateEncryptor()\n    $textBytes = [Text.Encoding]::UTF8.GetBytes($Text)\n    $encrypted = $encryptor.TransformFinalBlock($textBytes, 0, $textBytes.Length)\n    $result = [Text.Encoding]::UTF8.GetBytes('Salted__') + $salt + $encrypted\n    [Convert]::ToBase64String($result)\n}\nfunction New-VelvPayApiKey {\n    param(\n        [string]$SecretKey,\n        [string]$PublicKey,\n        [string]$ReferenceId,\n        [string]$EncryptionPassword\n    )\n    $payload = $SecretKey + $PublicKey + $ReferenceId\n    Encrypt-VelvPay -Text $payload -Password $EncryptionPassword\n}\n# Usage\n$apiKey = New-VelvPayApiKey `\n    -SecretKey 'sk_test_your_secret_key' `\n    -PublicKey 'pk_test_your_public_key' `\n    -ReferenceId 'ref_unique_123' `\n    -EncryptionPassword 'your_encryption_password'\nWrite-Host \"API Key: $apiKey\"\nWrite-Host \"Valid: $($apiKey.StartsWith('U2FsdGVkX1'))\"\n\n ```\n\n---\n\n## 15\\. Dart\n\n**pubspec.yaml dependencies:**\n\n``` yaml\ncrypto: ^3.0.3\nencrypt: ^5.0.1\n\n ```\n\n``` dart\nimport 'dart:convert';\nimport 'dart:math';\nimport 'dart:typed_data';\nimport 'package:crypto/crypto.dart';\nimport 'package:encrypt/encrypt.dart';\n({Uint8List key, Uint8List iv}) evpBytesToKey(List<int> password, Uint8List salt) {\n  final m = <Uint8List>[];\n  final data = Uint8List.fromList(password + salt);\n  for (var i = 0; i < 3; i++) {\n    final input = i > 0 ? Uint8List.fromList(m[i-1] + data) : data;\n    m.add(Uint8List.fromList(md5.convert(input).bytes));\n  }\n  final key = Uint8List.fromList(m[0] + m[1]);\n  final iv = Uint8List.fromList(m[2].take(16).toList());\n  return (key: key, iv: iv);\n}\nString encrypt(String text, String password) {\n  final random = Random.secure();\n  final salt = Uint8List.fromList(List.generate(8, (_) => random.nextInt(256)));\n  final keyIv = evpBytesToKey(utf8.encode(password), salt);\n  final encrypter = Encrypter(AES(Key(keyIv.key), mode: AESMode.cbc));\n  final encrypted = encrypter.encryptBytes(utf8.encode(text), iv: IV(keyIv.iv));\n  final result = Uint8List.fromList(\n    utf8.encode('Salted__') + salt + encrypted.bytes\n  );\n  return base64.encode(result);\n}\nString generateApiKey(String secretKey, String publicKey, String referenceId, \n                     String encryptionPassword) {\n  final payload = secretKey + publicKey + referenceId;\n  return encrypt(payload, encryptionPassword);\n}\n// Usage\nvoid main() {\n  final secretKey = 'sk_test_your_secret_key';\n  final publicKey = 'pk_test_your_public_key';\n  final referenceId = 'ref_unique_123';\n  final encryptionPassword = 'your_encryption_password';\n  final apiKey = generateApiKey(secretKey, publicKey, referenceId, encryptionPassword);\n  print('API Key: $apiKey');\n  print('Valid: ${apiKey.startsWith(\"U2FsdGVkX1\")}');\n}\n\n ```\n\n---\n\n## 16\\. cURL (Command Line API Request)\n\n``` bash\n#!/bin/bash\n# Generate API key\nSECRET_KEY=\"sk_test_your_secret_key\"\nPUBLIC_KEY=\"pk_test_your_public_key\"\nREFERENCE_ID=\"ref_unique_123\"\nENCRYPTION_PASSWORD=\"your_encryption_password\"\nPAYLOAD=\"${SECRET_KEY}${PUBLIC_KEY}${REFERENCE_ID}\"\nAPI_KEY=$(echo -n \"$PAYLOAD\" | openssl enc -aes-256-cbc -md md5 -salt -pass pass:\"$ENCRYPTION_PASSWORD\" -base64)\n# Make API request\ncurl -X GET \"https://api.velvpay.com/test\" \\\n  -H \"api-key: $API_KEY\" \\\n  -H \"public-key: $PUBLIC_KEY\" \\\n  -H \"reference-id: $REFERENCE_ID\"\n\n ```\n\n---\n\n## Usage Instructions\n\n1. **Choose your language** from the list above\n    \n2. **Copy the complete code** example\n    \n3. **Replace placeholder values:**\n    \n    - `sk_test_your_secret_key` → Your actual secret key\n        \n    - `pk_test_your_public_key` → Your actual public key\n        \n    - `ref_unique_123` → Your unique reference ID\n        \n    - `your_encryption_password` → Your encryption password\n        \n4. **Run the code** to generate the API key\n    \n5. **Verify** the output starts with `U2FsdGVkX1`\n    \n6. **Use** the generated API key in your API requests\n    \n\n---\n\n## Verification Checklist\n\n✅ Output starts with `U2FsdGVkX1`  \n✅ Output length is 88-128 characters  \n✅ Each encryption produces different output (random salt)  \n✅ All three headers are set in API request  \n✅ Payload concatenation has no separators\n\n---\n\n## Common Issues\n\n**Problem:** Output doesn't start with `U2FsdGVkX1`  \n**Solution:** Check that you're using MD5 for key derivation, not SHA256\n\n**Problem:** Same output every time  \n**Solution:** Ensure salt is randomly generated, not fixed\n\n**Problem:** Decryption fails  \n**Solution:** Verify EVP_BytesToKey implementation matches the specification\n\n---\n\nFor complete documentation, see the main VelvPay API Authentication Guide.\n\n# VelvPay API Key Generation - Code Examples\n\nComplete, copy-paste ready implementations for 20+ programming languages.\n\n---\n\n## 1\\. JavaScript (Browser - CryptoJS)\n\n``` html\n<comment class=&#x27;preserveHtml&#x27; class=&#x27;preserveHtml&#x27;> Include CryptoJS library  -->\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js\"></script>\n<script>\nfunction generateApiKey(secretKey, publicKey, referenceId, encryptionPassword) {\n    const payload = secretKey + publicKey + referenceId;\n    const apiKey = CryptoJS.AES.encrypt(payload, encryptionPassword).toString();\n    return apiKey;\n}\n// Usage\nconst secretKey = \"sk_test_your_secret_key\";\nconst publicKey = \"pk_test_your_public_key\";\nconst referenceId = \"ref_unique_123\";\nconst encryptionPassword = \"your_encryption_password\";\nconst apiKey = generateApiKey(secretKey, publicKey, referenceId, encryptionPassword);\nconsole.log(\"API Key:\", apiKey);\nconsole.log(\"Valid:\", apiKey.startsWith(\"U2FsdGVkX1\"));\n</script>\n\n ```\n\n---\n\n## 2\\. Node.js (Native Crypto)\n\n``` javascript\nconst crypto = require('crypto');\nfunction evpBytesToKey(password, salt, keyLen = 32, ivLen = 16) {\n    const md5 = (data) => crypto.createHash('md5').update(data).digest();\n    const data = Buffer.concat([Buffer.from(password, 'utf8'), salt]);\n    let d = md5(data);\n    let d1 = md5(Buffer.concat([d, data]));\n    let d2 = md5(Buffer.concat([d1, data]));\n    const key = Buffer.concat([d, d1]).slice(0, keyLen);\n    const iv = d2.slice(0, ivLen);\n    return { key, iv };\n}\nfunction encrypt(text, password) {\n    const salt = crypto.randomBytes(8);\n    const { key, iv } = evpBytesToKey(password, salt);\n    const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);\n    let encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]);\n    const result = Buffer.concat([\n        Buffer.from('Salted__', 'utf8'),\n        salt,\n        encrypted\n    ]);\n    return result.toString('base64');\n}\nfunction generateApiKey(secretKey, publicKey, referenceId, encryptionPassword) {\n    const payload = secretKey + publicKey + referenceId;\n    return encrypt(payload, encryptionPassword);\n}\n// Usage\nconst secretKey = \"sk_test_your_secret_key\";\nconst publicKey = \"pk_test_your_public_key\";\nconst referenceId = \"ref_unique_123\";\nconst encryptionPassword = \"your_encryption_password\";\nconst apiKey = generateApiKey(secretKey, publicKey, referenceId, encryptionPassword);\nconsole.log(\"API Key:\", apiKey);\nconsole.log(\"Valid:\", apiKey.startsWith(\"U2FsdGVkX1\"));\n\n ```\n\n---\n\n## 3\\. Python\n\n**Install:** `pip install pycryptodome`\n\n``` python\nfrom Crypto.Cipher import AES\nfrom Crypto.Random import get_random_bytes\nimport hashlib\nimport base64\ndef evp_bytes_to_key(password, salt, key_len=32, iv_len=16):\n    m = []\n    data = password.encode('utf-8') + salt\n    for i in range(3):\n        if i == 0:\n            m.append(hashlib.md5(data).digest())\n        else:\n            m.append(hashlib.md5(m[i-1] + data).digest())\n    key = b''.join(m[:2])[:key_len]\n    iv = m[2][:iv_len]\n    return key, iv\ndef pkcs7_pad(data, block_size=16):\n    pad_len = block_size - (len(data) % block_size)\n    return data + bytes([pad_len] * pad_len)\ndef encrypt(text, password):\n    salt = get_random_bytes(8)\n    key, iv = evp_bytes_to_key(password, salt)\n    cipher = AES.new(key, AES.MODE_CBC, iv)\n    padded_text = pkcs7_pad(text.encode('utf-8'))\n    encrypted = cipher.encrypt(padded_text)\n    result = b'Salted__' + salt + encrypted\n    return base64.b64encode(result).decode('utf-8')\ndef generate_api_key(secret_key, public_key, reference_id, encryption_password):\n    payload = secret_key + public_key + reference_id\n    return encrypt(payload, encryption_password)\n# Usage\nsecret_key = \"sk_test_your_secret_key\"\npublic_key = \"pk_test_your_public_key\"\nreference_id = \"ref_unique_123\"\nencryption_password = \"your_encryption_password\"\napi_key = generate_api_key(secret_key, public_key, reference_id, encryption_password)\nprint(f\"API Key: {api_key}\")\nprint(f\"Valid: {api_key.startswith('U2FsdGVkX1')}\")\n\n ```\n\n---\n\n## 4\\. PHP\n\n``` php\nfunction evpBytesToKey($password, $salt, $keyLen = 32, $ivLen = 16) {\n    $data = $password . $salt;\n    $m = [];\n    for ($i = 0; $i < 3; $i++) {\n        if ($i == 0) {\n            $m[] = md5($data, true);\n        } else {\n            $m[] = md5($m[$i-1] . $data, true);\n        }\n    }\n    $key = substr($m[0] . $m[1], 0, $keyLen);\n    $iv = substr($m[2], 0, $ivLen);\n    return [$key, $iv];\n}\nfunction encrypt($text, $password) {\n    $salt = openssl_random_pseudo_bytes(8);\n    list($key, $iv) = evpBytesToKey($password, $salt);\n    $encrypted = openssl_encrypt($text, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);\n    $result = 'Salted__' . $salt . $encrypted;\n    return base64_encode($result);\n}\nfunction generateApiKey($secretKey, $publicKey, $referenceId, $encryptionPassword) {\n    $payload = $secretKey . $publicKey . $referenceId;\n    return encrypt($payload, $encryptionPassword);\n}\n// Usage\n$secretKey = \"sk_test_your_secret_key\";\n$publicKey = \"pk_test_your_public_key\";\n$referenceId = \"ref_unique_123\";\n$encryptionPassword = \"your_encryption_password\";\n$apiKey = generateApiKey($secretKey, $publicKey, $referenceId, $encryptionPassword);\necho \"API Key: \" . $apiKey . \"\\n\";\necho \"Valid: \" . (strpos($apiKey, 'U2FsdGVkX1') === 0 ? 'true' : 'false') . \"\\n\";\n?>\n\n ```\n\n---\n\n## 5\\. Ruby\n\n``` ruby\nrequire 'openssl'\nrequire 'base64'\ndef evp_bytes_to_key(password, salt, key_len = 32, iv_len = 16)\n  data = password + salt\n  m = []\n  3.times do |i|\n    if i == 0\n      m << OpenSSL::Digest::MD5.digest(data)\n    else\n      m << OpenSSL::Digest::MD5.digest(m[i-1] + data)\n    end\n  end\n  key = (m[0] + m[1])[0, key_len]\n  iv = m[2][0, iv_len]\n  [key, iv]\nend\ndef encrypt(text, password)\n  salt = OpenSSL::Random.random_bytes(8)\n  key, iv = evp_bytes_to_key(password, salt)\n  cipher = OpenSSL::Cipher.new('aes-256-cbc')\n  cipher.encrypt\n  cipher.key = key\n  cipher.iv = iv\n  encrypted = cipher.update(text) + cipher.final\n  result = 'Salted__' + salt + encrypted\n  Base64.strict_encode64(result)\nend\ndef generate_api_key(secret_key, public_key, reference_id, encryption_password)\n  payload = secret_key + public_key + reference_id\n  encrypt(payload, encryption_password)\nend\n# Usage\nsecret_key = \"sk_test_your_secret_key\"\npublic_key = \"pk_test_your_public_key\"\nreference_id = \"ref_unique_123\"\nencryption_password = \"your_encryption_password\"\napi_key = generate_api_key(secret_key, public_key, reference_id, encryption_password)\nputs \"API Key: #{api_key}\"\nputs \"Valid: #{api_key.start_with?('U2FsdGVkX1')}\"\n\n ```\n\n---\n\n## 6\\. Java\n\n``` java\nimport javax.crypto.*;\nimport javax.crypto.spec.*;\nimport java.security.*;\nimport java.util.Base64;\nimport java.util.Arrays;\npublic class VelvPayEncryption {\n    private static byte[][] evpBytesToKey(byte[] password, byte[] salt) throws Exception {\n        MessageDigest md = MessageDigest.getInstance(\"MD5\");\n        byte[][] m = new byte[3][];\n        for (int i = 0; i < 3; i++) {\n            md.reset();\n            if (i > 0) md.update(m[i-1]);\n            md.update(password);\n            md.update(salt);\n            m[i] = md.digest();\n        }\n        byte[] key = new byte[32];\n        System.arraycopy(m[0], 0, key, 0, 16);\n        System.arraycopy(m[1], 0, key, 16, 16);\n        byte[] iv = Arrays.copyOf(m[2], 16);\n        return new byte[][] {key, iv};\n    }\n    public static String encrypt(String text, String password) throws Exception {\n        byte[] salt = new byte[8];\n        new SecureRandom().nextBytes(salt);\n        byte[][] keyIv = evpBytesToKey(password.getBytes(\"UTF-8\"), salt);\n        Cipher cipher = Cipher.getInstance(\"AES/CBC/PKCS5Padding\");\n        cipher.init(Cipher.ENCRYPT_MODE, \n                   new SecretKeySpec(keyIv[0], \"AES\"), \n                   new IvParameterSpec(keyIv[1]));\n        byte[] encrypted = cipher.doFinal(text.getBytes(\"UTF-8\"));\n        byte[] result = new byte[16 + encrypted.length];\n        System.arraycopy(\"Salted__\".getBytes(\"UTF-8\"), 0, result, 0, 8);\n        System.arraycopy(salt, 0, result, 8, 8);\n        System.arraycopy(encrypted, 0, result, 16, encrypted.length);\n        return Base64.getEncoder().encodeToString(result);\n    }\n    public static String generateApiKey(String secretKey, String publicKey, \n                                       String referenceId, String encryptionPassword) \n                                       throws Exception {\n        String payload = secretKey + publicKey + referenceId;\n        return encrypt(payload, encryptionPassword);\n    }\n    public static void main(String[] args) throws Exception {\n        String secretKey = \"sk_test_your_secret_key\";\n        String publicKey = \"pk_test_your_public_key\";\n        String referenceId = \"ref_unique_123\";\n        String encryptionPassword = \"your_encryption_password\";\n        String apiKey = generateApiKey(secretKey, publicKey, referenceId, encryptionPassword);\n        System.out.println(\"API Key: \" + apiKey);\n        System.out.println(\"Valid: \" + apiKey.startsWith(\"U2FsdGVkX1\"));\n    }\n}\n\n ```\n\n---\n\n## 7\\. Go\n\n``` go\npackage main\nimport (\n    \"crypto/aes\"\n    \"crypto/cipher\"\n    \"crypto/md5\"\n    \"crypto/rand\"\n    \"encoding/base64\"\n    \"fmt\"\n)\nfunc evpBytesToKey(password, salt []byte) ([]byte, []byte) {\n    var m [][]byte\n    data := append(password, salt...)\n    for i := 0; i < 3; i++ {\n        h := md5.New()\n        if i > 0 {\n            h.Write(m[i-1])\n        }\n        h.Write(data)\n        m = append(m, h.Sum(nil))\n    }\n    key := append(m[0], m[1]...)\n    iv := m[2]\n    return key, iv\n}\nfunc pkcs7Pad(data []byte, blockSize int) []byte {\n    padding := blockSize - (len(data) % blockSize)\n    padText := make([]byte, padding)\n    for i := range padText {\n        padText[i] = byte(padding)\n    }\n    return append(data, padText...)\n}\nfunc encrypt(text, password string) (string, error) {\n    salt := make([]byte, 8)\n    if _, err := rand.Read(salt); err != nil {\n        return \"\", err\n    }\n    key, iv := evpBytesToKey([]byte(password), salt)\n    block, err := aes.NewCipher(key)\n    if err != nil {\n        return \"\", err\n    }\n    plaintext := pkcs7Pad([]byte(text), aes.BlockSize)\n    ciphertext := make([]byte, len(plaintext))\n    mode := cipher.NewCBCEncrypter(block, iv)\n    mode.CryptBlocks(ciphertext, plaintext)\n    result := append([]byte(\"Salted__\"), append(salt, ciphertext...)...)\n    return base64.StdEncoding.EncodeToString(result), nil\n}\nfunc generateApiKey(secretKey, publicKey, referenceId, encryptionPassword string) (string, error) {\n    payload := secretKey + publicKey + referenceId\n    return encrypt(payload, encryptionPassword)\n}\nfunc main() {\n    secretKey := \"sk_test_your_secret_key\"\n    publicKey := \"pk_test_your_public_key\"\n    referenceId := \"ref_unique_123\"\n    encryptionPassword := \"your_encryption_password\"\n    apiKey, err := generateApiKey(secretKey, publicKey, referenceId, encryptionPassword)\n    if err != nil {\n        panic(err)\n    }\n    fmt.Println(\"API Key:\", apiKey)\n    fmt.Println(\"Valid:\", apiKey[:10] == \"U2FsdGVkX1\")\n}\n\n ```\n\n---\n\n## 8\\. C#\n\n``` csharp\nusing System;\nusing System.IO;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Text;\npublic class VelvPayEncryption\n{\n    private static (byte[], byte[]) EvpBytesToKey(byte[] password, byte[] salt)\n    {\n        using (var md5 = MD5.Create())\n        {\n            var m = new byte[3][];\n            var data = password.Concat(salt).ToArray();\n            for (int i = 0; i < 3; i++)\n            {\n                if (i == 0)\n                {\n                    m[i] = md5.ComputeHash(data);\n                }\n                else\n                {\n                    m[i] = md5.ComputeHash(m[i-1].Concat(data).ToArray());\n                }\n            }\n            var key = m[0].Concat(m[1]).ToArray();\n            var iv = m[2].Take(16).ToArray();\n            return (key, iv);\n        }\n    }\n    public static string Encrypt(string text, string password)\n    {\n        byte[] salt = new byte[8];\n        using (var rng = RandomNumberGenerator.Create())\n        {\n            rng.GetBytes(salt);\n        }\n        var (key, iv) = EvpBytesToKey(Encoding.UTF8.GetBytes(password), salt);\n        using (var aes = Aes.Create())\n        {\n            aes.Key = key;\n            aes.IV = iv;\n            aes.Mode = CipherMode.CBC;\n            aes.Padding = PaddingMode.PKCS7;\n            using (var encryptor = aes.CreateEncryptor())\n            {\n                byte[] encrypted = encryptor.TransformFinalBlock(\n                    Encoding.UTF8.GetBytes(text), 0, text.Length);\n                byte[] result = Encoding.UTF8.GetBytes(\"Salted__\")\n                    .Concat(salt)\n                    .Concat(encrypted)\n                    .ToArray();\n                return Convert.ToBase64String(result);\n            }\n        }\n    }\n    public static string GenerateApiKey(string secretKey, string publicKey, \n                                       string referenceId, string encryptionPassword)\n    {\n        string payload = secretKey + publicKey + referenceId;\n        return Encrypt(payload, encryptionPassword);\n    }\n    public static void Main()\n    {\n        string secretKey = \"sk_test_your_secret_key\";\n        string publicKey = \"pk_test_your_public_key\";\n        string referenceId = \"ref_unique_123\";\n        string encryptionPassword = \"your_encryption_password\";\n        string apiKey = GenerateApiKey(secretKey, publicKey, referenceId, encryptionPassword);\n        Console.WriteLine($\"API Key: {apiKey}\");\n        Console.WriteLine($\"Valid: {apiKey.StartsWith(\"U2FsdGVkX1\")}\");\n    }\n}\n\n ```\n\n---\n\n## 9\\. Kotlin\n\n``` kotlin\nimport javax.crypto.Cipher\nimport javax.crypto.spec.IvParameterSpec\nimport javax.crypto.spec.SecretKeySpec\nimport java.security.MessageDigest\nimport java.security.SecureRandom\nimport java.util.Base64\nfun evpBytesToKey(password: ByteArray, salt: ByteArray): Pair<ByteArray, ByteArray> {\n    val md = MessageDigest.getInstance(\"MD5\")\n    val m = mutableListOf<ByteArray>()\n    val data = password + salt\n    repeat(3) { i ->\n        md.reset()\n        if (i > 0) md.update(m[i-1])\n        md.update(data)\n        m.add(md.digest())\n    }\n    val key = m[0] + m[1]\n    val iv = m[2].take(16).toByteArray()\n    return Pair(key, iv)\n}\nfun encrypt(text: String, password: String): String {\n    val salt = ByteArray(8).apply { SecureRandom().nextBytes(this) }\n    val (key, iv) = evpBytesToKey(password.toByteArray(), salt)\n    val cipher = Cipher.getInstance(\"AES/CBC/PKCS5Padding\")\n    cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, \"AES\"), IvParameterSpec(iv))\n    val encrypted = cipher.doFinal(text.toByteArray())\n    val result = \"Salted__\".toByteArray() + salt + encrypted\n    return Base64.getEncoder().encodeToString(result)\n}\nfun generateApiKey(secretKey: String, publicKey: String, referenceId: String, \n                  encryptionPassword: String): String {\n    val payload = secretKey + publicKey + referenceId\n    return encrypt(payload, encryptionPassword)\n}\n// Usage\nfun main() {\n    val secretKey = \"sk_test_your_secret_key\"\n    val publicKey = \"pk_test_your_public_key\"\n    val referenceId = \"ref_unique_123\"\n    val encryptionPassword = \"your_encryption_password\"\n    val apiKey = generateApiKey(secretKey, publicKey, referenceId, encryptionPassword)\n    println(\"API Key: $apiKey\")\n    println(\"Valid: ${apiKey.startsWith(\"U2FsdGVkX1\")}\")\n}\n\n ```\n\n---\n\n## 10\\. Swift\n\n``` swift\nimport Foundation\nimport CommonCrypto\nfunc evpBytesToKey(password: String, salt: [UInt8]) -> ([UInt8], [UInt8]) {\n    var m: [[UInt8]] = []\n    let passwordBytes = Array(password.utf8)\n    let data = passwordBytes + salt\n    for i in 0..<3 {\n        var hash = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))\n        var input = i > 0 ? m[i-1] + data : data\n        CC_MD5(&input, CC_LONG(input.count), &hash)\n        m.append(hash)\n    }\n    let key = m[0] + m[1]\n    let iv = Array(m[2].prefix(16))\n    return (key, iv)\n}\nfunc encrypt(text: String, password: String) -> String? {\n    let salt = (0..<8).map { _ in UInt8.random(in: 0...255) }\n    let (key, iv) = evpBytesToKey(password: password, salt: salt)\n    guard let textData = text.data(using: .utf8) else { return nil }\n    let bufferSize = textData.count + kCCBlockSizeAES128\n    var buffer = [UInt8](repeating: 0, count: bufferSize)\n    var numBytesEncrypted = 0\n    let cryptStatus = CCCrypt(\n        CCOperation(kCCEncrypt),\n        CCAlgorithm(kCCAlgorithmAES),\n        CCOptions(kCCOptionPKCS7Padding),\n        key, key.count,\n        iv,\n        [UInt8](textData), textData.count,\n        &buffer, bufferSize,\n        &numBytesEncrypted\n    )\n    guard cryptStatus == kCCSuccess else { return nil }\n    let encrypted = Array(buffer.prefix(numBytesEncrypted))\n    let result = Array(\"Salted__\".utf8) + salt + encrypted\n    return Data(result).base64EncodedString()\n}\nfunc generateApiKey(secretKey: String, publicKey: String, referenceId: String, \n                   encryptionPassword: String) -> String? {\n    let payload = secretKey + publicKey + referenceId\n    return encrypt(text: payload, password: encryptionPassword)\n}\n// Usage\nlet secretKey = \"sk_test_your_secret_key\"\nlet publicKey = \"pk_test_your_public_key\"\nlet referenceId = \"ref_unique_123\"\nlet encryptionPassword = \"your_encryption_password\"\nif let apiKey = generateApiKey(secretKey: secretKey, publicKey: publicKey, \n                               referenceId: referenceId, \n                               encryptionPassword: encryptionPassword) {\n    print(\"API Key: \\(apiKey)\")\n    print(\"Valid: \\(apiKey.hasPrefix(\"U2FsdGVkX1\"))\")\n}\n\n ```\n\n---\n\n## 11\\. Rust\n\n**Cargo.toml dependencies:**\n\n``` toml\naes = \"0.8\"\nblock-modes = \"0.9\"\nmd5 = \"0.7\"\nrand = \"0.8\"\nbase64 = \"0.21\"\n\n ```\n\n``` rust\nuse aes::Aes256;\nuse block_modes::{BlockMode, Cbc};\nuse block_modes::block_padding::Pkcs7;\nuse md5::{Md5, Digest};\nuse rand::Rng;\nuse base64::{Engine as _, engine::general_purpose};\ntype Aes256Cbc = Cbc<Aes256, Pkcs7>;\nfn evp_bytes_to_key(password: &[u8], salt: &[u8]) -> (Vec<u8>, Vec<u8>) {\n    let mut m: Vec<Vec<u8>> = Vec::new();\n    let data: Vec<u8> = password.iter().chain(salt.iter()).copied().collect();\n    for i in 0..3 {\n        let mut hasher = Md5::new();\n        if i > 0 {\n            hasher.update(&m[i-1]);\n        }\n        hasher.update(&data);\n        m.push(hasher.finalize().to_vec());\n    }\n    let key: Vec<u8> = m[0].iter().chain(m[1].iter()).copied().collect();\n    let iv = m[2][..16].to_vec();\n    (key, iv)\n}\nfn encrypt(text: &str, password: &str) -> String {\n    let mut rng = rand::thread_rng();\n    let salt: Vec<u8> = (0..8).map(|_| rng.gen()).collect();\n    let (key, iv) = evp_bytes_to_key(password.as_bytes(), &salt);\n    let cipher = Aes256Cbc::new_from_slices(&key, &iv).unwrap();\n    let ciphertext = cipher.encrypt_vec(text.as_bytes());\n    let mut result = b\"Salted__\".to_vec();\n    result.extend_from_slice(&salt);\n    result.extend_from_slice(&ciphertext);\n    general_purpose::STANDARD.encode(&result)\n}\nfn generate_api_key(secret_key: &str, public_key: &str, reference_id: &str, \n                   encryption_password: &str) -> String {\n    let payload = format!(\"{}{}{}\", secret_key, public_key, reference_id);\n    encrypt(&payload, encryption_password)\n}\nfn main() {\n    let secret_key = \"sk_test_your_secret_key\";\n    let public_key = \"pk_test_your_public_key\";\n    let reference_id = \"ref_unique_123\";\n    let encryption_password = \"your_encryption_password\";\n    let api_key = generate_api_key(secret_key, public_key, reference_id, encryption_password);\n    println!(\"API Key: {}\", api_key);\n    println!(\"Valid: {}\", api_key.starts_with(\"U2FsdGVkX1\"));\n}\n\n ```\n\n---\n\n## 12\\. TypeScript\n\n**Install:** `npm install crypto-js @types/crypto-js`\n\n``` typescript\nimport CryptoJS from 'crypto-js';\nfunction generateApiKey(\n    secretKey: string, \n    publicKey: string, \n    referenceId: string, \n    encryptionPassword: string\n): string {\n    const payload = secretKey + publicKey + referenceId;\n    return CryptoJS.AES.encrypt(payload, encryptionPassword).toString();\n}\n// Usage\nconst secretKey: string = \"sk_test_your_secret_key\";\nconst publicKey: string = \"pk_test_your_public_key\";\nconst referenceId: string = \"ref_unique_123\";\nconst encryptionPassword: string = \"your_encryption_password\";\nconst apiKey: string = generateApiKey(secretKey, publicKey, referenceId, encryptionPassword);\nconsole.log(\"API Key:\", apiKey);\nconsole.log(\"Valid:\", apiKey.startsWith(\"U2FsdGVkX1\"));\n\n ```\n\n---\n\n## 13\\. Bash/Shell\n\n``` bash\n#!/bin/bash\ngenerate_api_key() {\n    local secret_key=\"$1\"\n    local public_key=\"$2\"\n    local reference_id=\"$3\"\n    local encryption_password=\"$4\"\n    local payload=\"${secret_key}${public_key}${reference_id}\"\n    # Using OpenSSL with MD5 key derivation (legacy)\n    echo -n \"$payload\" | openssl enc -aes-256-cbc -md md5 -salt \\\n        -pass pass:\"$encryption_password\" -base64\n}\n# Usage\nSECRET_KEY=\"sk_test_your_secret_key\"\nPUBLIC_KEY=\"pk_test_your_public_key\"\nREFERENCE_ID=\"ref_unique_123\"\nENCRYPTION_PASSWORD=\"your_encryption_password\"\nAPI_KEY=$(generate_api_key \"$SECRET_KEY\" \"$PUBLIC_KEY\" \"$REFERENCE_ID\" \"$ENCRYPTION_PASSWORD\")\necho \"API Key: $API_KEY\"\n\n ```\n\n---\n\n## 14\\. PowerShell\n\n``` powershell\nfunction Get-EVPBytesToKey {\n    param([byte[]]$Password, [byte[]]$Salt)\n    $md5 = [System.Security.Cryptography.MD5]::Create()\n    $m = @()\n    $data = $Password + $Salt\n    for ($i = 0; $i -lt 3; $i++) {\n        if ($i -eq 0) {\n            $m += ,$md5.ComputeHash($data)\n        } else {\n            $m += ,$md5.ComputeHash($m[$i-1] + $data)\n        }\n    }\n    $key = $m[0] + $m[1]\n    $iv = $m[2][0..15]\n    @{ Key = $key; IV = $iv }\n}\nfunction Encrypt-VelvPay {\n    param([string]$Text, [string]$Password)\n    $salt = New-Object byte[] 8\n    $rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()\n    $rng.GetBytes($salt)\n    $keyIv = Get-EVPBytesToKey -Password ([Text.Encoding]::UTF8.GetBytes($Password)) -Salt $salt\n    $aes = [System.Security.Cryptography.Aes]::Create()\n    $aes.Key = $keyIv.Key\n    $aes.IV = $keyIv.IV\n    $aes.Mode = [System.Security.Cryptography.CipherMode]::CBC\n    $aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7\n    $encryptor = $aes.CreateEncryptor()\n    $textBytes = [Text.Encoding]::UTF8.GetBytes($Text)\n    $encrypted = $encryptor.TransformFinalBlock($textBytes, 0, $textBytes.Length)\n    $result = [Text.Encoding]::UTF8.GetBytes('Salted__') + $salt + $encrypted\n    [Convert]::ToBase64String($result)\n}\nfunction New-VelvPayApiKey {\n    param(\n        [string]$SecretKey,\n        [string]$PublicKey,\n        [string]$ReferenceId,\n        [string]$EncryptionPassword\n    )\n    $payload = $SecretKey + $PublicKey + $ReferenceId\n    Encrypt-VelvPay -Text $payload -Password $EncryptionPassword\n}\n# Usage\n$apiKey = New-VelvPayApiKey `\n    -SecretKey 'sk_test_your_secret_key' `\n    -PublicKey 'pk_test_your_public_key' `\n    -ReferenceId 'ref_unique_123' `\n    -EncryptionPassword 'your_encryption_password'\nWrite-Host \"API Key: $apiKey\"\nWrite-Host \"Valid: $($apiKey.StartsWith('U2FsdGVkX1'))\"\n\n ```\n\n---\n\n## 15\\. Dart\n\n**pubspec.yaml dependencies:**\n\n``` yaml\ncrypto: ^3.0.3\nencrypt: ^5.0.1\n\n ```\n\n``` dart\nimport 'dart:convert';\nimport 'dart:math';\nimport 'dart:typed_data';\nimport 'package:crypto/crypto.dart';\nimport 'package:encrypt/encrypt.dart';\n({Uint8List key, Uint8List iv}) evpBytesToKey(List<int> password, Uint8List salt) {\n  final m = <Uint8List>[];\n  final data = Uint8List.fromList(password + salt);\n  for (var i = 0; i < 3; i++) {\n    final input = i > 0 ? Uint8List.fromList(m[i-1] + data) : data;\n    m.add(Uint8List.fromList(md5.convert(input).bytes));\n  }\n  final key = Uint8List.fromList(m[0] + m[1]);\n  final iv = Uint8List.fromList(m[2].take(16).toList());\n  return (key: key, iv: iv);\n}\nString encrypt(String text, String password) {\n  final random = Random.secure();\n  final salt = Uint8List.fromList(List.generate(8, (_) => random.nextInt(256)));\n  final keyIv = evpBytesToKey(utf8.encode(password), salt);\n  final encrypter = Encrypter(AES(Key(keyIv.key), mode: AESMode.cbc));\n  final encrypted = encrypter.encryptBytes(utf8.encode(text), iv: IV(keyIv.iv));\n  final result = Uint8List.fromList(\n    utf8.encode('Salted__') + salt + encrypted.bytes\n  );\n  return base64.encode(result);\n}\nString generateApiKey(String secretKey, String publicKey, String referenceId, \n                     String encryptionPassword) {\n  final payload = secretKey + publicKey + referenceId;\n  return encrypt(payload, encryptionPassword);\n}\n// Usage\nvoid main() {\n  final secretKey = 'sk_test_your_secret_key';\n  final publicKey = 'pk_test_your_public_key';\n  final referenceId = 'ref_unique_123';\n  final encryptionPassword = 'your_encryption_password';\n  final apiKey = generateApiKey(secretKey, publicKey, referenceId, encryptionPassword);\n  print('API Key: $apiKey');\n  print('Valid: ${apiKey.startsWith(\"U2FsdGVkX1\")}');\n}\n\n ```\n\n---\n\n## 16\\. cURL (Command Line API Request)\n\n``` bash\n#!/bin/bash\n# Generate API key\nSECRET_KEY=\"sk_test_your_secret_key\"\nPUBLIC_KEY=\"pk_test_your_public_key\"\nREFERENCE_ID=\"ref_unique_123\"\nENCRYPTION_PASSWORD=\"your_encryption_password\"\nPAYLOAD=\"${SECRET_KEY}${PUBLIC_KEY}${REFERENCE_ID}\"\nAPI_KEY=$(echo -n \"$PAYLOAD\" | openssl enc -aes-256-cbc -md md5 -salt -pass pass:\"$ENCRYPTION_PASSWORD\" -base64)\n# Make API request\ncurl -X GET \"https://api.velvpay.com/test\" \\\n  -H \"api-key: $API_KEY\" \\\n  -H \"public-key: $PUBLIC_KEY\" \\\n  -H \"reference-id: $REFERENCE_ID\"\n\n ```\n\n---\n\n## Usage Instructions\n\n1. **Choose your language** from the list above\n    \n2. **Copy the complete code** example\n    \n3. **Replace placeholder values:**\n    \n    - `sk_test_your_secret_key` → Your actual secret key\n        \n    - `pk_test_your_public_key` → Your actual public key\n        \n    - `ref_unique_123` → Your unique reference ID\n        \n    - `your_encryption_password` → Your encryption password\n        \n4. **Run the code** to generate the API key\n    \n5. **Verify** the output starts with `U2FsdGVkX1`\n    \n6. **Use** the generated API key in your API requests\n    \n\n---\n\n## Verification Checklist\n\n✅ Output starts with `U2FsdGVkX1`  \n✅ Output length is 88-128 characters  \n✅ Each encryption produces different output (random salt)  \n✅ All three headers are set in API request  \n✅ Payload concatenation has no separators\n\n---\n\n## Common Issues\n\n**Problem:** Output doesn't start with `U2FsdGVkX1`  \n**Solution:** Check that you're using MD5 for key derivation, not SHA256\n\n**Problem:** Same output every time  \n**Solution:** Ensure salt is randomly generated, not fixed\n\n**Problem:** Decryption fails  \n**Solution:** Verify EVP_BytesToKey implementation matches the specification\n\n---\n\nFor complete documentation, see the main VelvPay API Authentication Guide.\n\nEach example includes:\n\n- Complete EVP_BytesToKey implementation\n    \n- Full encryption function\n    \n- Usage examples\n    \n- Test output\n    \n\n---\n\n## SECURITY NOTES\n\n1. Never log or expose your secret_key in production\n    \n2. Always use HTTPS for API requests\n    \n3. Store encryption_password (your encryption key) securely (environment variables, secrets manager)\n    \n4. Rotate keys periodically\n    \n5. Use cryptographically secure random number generators for salt\n    \n6. Validate all inputs before encryption\n    \n\n---\n\n## VERSION INFORMATION\n\nEncryption Format: OpenSSL Salted__ (legacy)  \nAES Mode: CBC  \nKey Size: 256 bits  \nBlock Size: 128 bits  \nPadding: PKCS7  \nKey Derivation: EVP_BytesToKey (MD5, 1 iteration)  \nEncoding: Base64","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","isPublicCollection":false,"owner":"36526309","team":6307359,"collectionId":"f551ee5c-3ee2-4685-a5d3-c63e2532180a","publishedId":"2sA3XY7J6K","public":true,"publicUrl":"https://documenter-api.postman.tech/view/36526309/2sA3XY7J6K","privateUrl":"https://go.postman.co/documentation/36526309-f551ee5c-3ee2-4685-a5d3-c63e2532180a","customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"19807D"},"documentationLayout":"classic-single-column","customisation":{"metaTags":[{"name":"description","value":"Welcome to the VelvPay API documentation! VelvPay is a payment service that allows you to integrate payment solutions seamlessly into your applications. This documentation will guide you through the API endpoints, usage, and best practices."},{"name":"title","value":"Velvpay Api"}],"appearance":{"default":"light","themes":[{"name":"dark","logo":"https://content.pstmn.io/547d5769-4061-4295-ad10-d55e89c108dd/dmVsdnBheSByb3VuZC5wbmc=","colors":{"top-bar":"212121","right-sidebar":"303030","highlight":"19807D"}},{"name":"light","logo":"https://content.pstmn.io/a048928d-7418-45a6-a9f8-042fe6de1ece/dmVsdnBheSByb3VuZC5wbmc=","colors":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"19807D"}}]}},"version":"8.12.12","publishDate":"2024-06-25T02:17:03.000Z","activeVersionTag":"latest","documentationTheme":"light","metaTags":{"title":"Velvpay Api","description":"Welcome to the VelvPay API documentation! VelvPay is a payment service that allows you to integrate payment solutions seamlessly into your applications. This documentation will guide you through the API endpoints, usage, and best practices."},"logos":{"logoLight":"https://content.pstmn.io/a048928d-7418-45a6-a9f8-042fe6de1ece/dmVsdnBheSByb3VuZC5wbmc=","logoDark":"https://content.pstmn.io/547d5769-4061-4295-ad10-d55e89c108dd/dmVsdnBheSByb3VuZC5wbmc="}},"statusCode":200},"environments":[],"user":{"authenticated":false,"permissions":{"publish":false}},"run":{"button":{"js":"https://run.pstmn.io/button.js","css":"https://run.pstmn.io/button.css"}},"web":"https://www.getpostman.com/","team":{"logo":"https://res.cloudinary.com/postman/image/upload/t_team_logo_pubdoc/v1/team/4abe31e4836064e51fd3762daccc2b43f72833b9f42f42bc28ca10be6bafe19a","favicon":"https://res.cloudinary.com/postman/image/upload/v1719262528/team/j49vcbd8ac3vkke9eigs.ico"},"isEnvFetchError":false,"languages":"[{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"HttpClient\"},{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"RestSharp\"},{\"key\":\"curl\",\"label\":\"cURL\",\"variant\":\"cURL\"},{\"key\":\"dart\",\"label\":\"Dart\",\"variant\":\"http\"},{\"key\":\"go\",\"label\":\"Go\",\"variant\":\"Native\"},{\"key\":\"http\",\"label\":\"HTTP\",\"variant\":\"HTTP\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"OkHttp\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"Unirest\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"Fetch\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"jQuery\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"XHR\"},{\"key\":\"c\",\"label\":\"C\",\"variant\":\"libcurl\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Axios\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Native\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Request\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Unirest\"},{\"key\":\"objective-c\",\"label\":\"Objective-C\",\"variant\":\"NSURLSession\"},{\"key\":\"ocaml\",\"label\":\"OCaml\",\"variant\":\"Cohttp\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"cURL\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"Guzzle\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"HTTP_Request2\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"pecl_http\"},{\"key\":\"powershell\",\"label\":\"PowerShell\",\"variant\":\"RestMethod\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"http.client\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"Requests\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"httr\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"RCurl\"},{\"key\":\"ruby\",\"label\":\"Ruby\",\"variant\":\"Net::HTTP\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"Httpie\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"wget\"},{\"key\":\"swift\",\"label\":\"Swift\",\"variant\":\"URLSession\"}]","languageSettings":[{"key":"csharp","label":"C#","variant":"HttpClient"},{"key":"csharp","label":"C#","variant":"RestSharp"},{"key":"curl","label":"cURL","variant":"cURL"},{"key":"dart","label":"Dart","variant":"http"},{"key":"go","label":"Go","variant":"Native"},{"key":"http","label":"HTTP","variant":"HTTP"},{"key":"java","label":"Java","variant":"OkHttp"},{"key":"java","label":"Java","variant":"Unirest"},{"key":"javascript","label":"JavaScript","variant":"Fetch"},{"key":"javascript","label":"JavaScript","variant":"jQuery"},{"key":"javascript","label":"JavaScript","variant":"XHR"},{"key":"c","label":"C","variant":"libcurl"},{"key":"nodejs","label":"NodeJs","variant":"Axios"},{"key":"nodejs","label":"NodeJs","variant":"Native"},{"key":"nodejs","label":"NodeJs","variant":"Request"},{"key":"nodejs","label":"NodeJs","variant":"Unirest"},{"key":"objective-c","label":"Objective-C","variant":"NSURLSession"},{"key":"ocaml","label":"OCaml","variant":"Cohttp"},{"key":"php","label":"PHP","variant":"cURL"},{"key":"php","label":"PHP","variant":"Guzzle"},{"key":"php","label":"PHP","variant":"HTTP_Request2"},{"key":"php","label":"PHP","variant":"pecl_http"},{"key":"powershell","label":"PowerShell","variant":"RestMethod"},{"key":"python","label":"Python","variant":"http.client"},{"key":"python","label":"Python","variant":"Requests"},{"key":"r","label":"R","variant":"httr"},{"key":"r","label":"R","variant":"RCurl"},{"key":"ruby","label":"Ruby","variant":"Net::HTTP"},{"key":"shell","label":"Shell","variant":"Httpie"},{"key":"shell","label":"Shell","variant":"wget"},{"key":"swift","label":"Swift","variant":"URLSession"}],"languageOptions":[{"label":"C# - HttpClient","value":"csharp - HttpClient - C#"},{"label":"C# - RestSharp","value":"csharp - RestSharp - C#"},{"label":"cURL - cURL","value":"curl - cURL - cURL"},{"label":"Dart - http","value":"dart - http - Dart"},{"label":"Go - Native","value":"go - Native - Go"},{"label":"HTTP - HTTP","value":"http - HTTP - HTTP"},{"label":"Java - OkHttp","value":"java - OkHttp - Java"},{"label":"Java - Unirest","value":"java - Unirest - Java"},{"label":"JavaScript - Fetch","value":"javascript - Fetch - JavaScript"},{"label":"JavaScript - jQuery","value":"javascript - jQuery - JavaScript"},{"label":"JavaScript - XHR","value":"javascript - XHR - JavaScript"},{"label":"C - libcurl","value":"c - libcurl - C"},{"label":"NodeJs - Axios","value":"nodejs - Axios - NodeJs"},{"label":"NodeJs - Native","value":"nodejs - Native - NodeJs"},{"label":"NodeJs - Request","value":"nodejs - Request - NodeJs"},{"label":"NodeJs - Unirest","value":"nodejs - Unirest - NodeJs"},{"label":"Objective-C - NSURLSession","value":"objective-c - NSURLSession - Objective-C"},{"label":"OCaml - Cohttp","value":"ocaml - Cohttp - OCaml"},{"label":"PHP - cURL","value":"php - cURL - PHP"},{"label":"PHP - Guzzle","value":"php - Guzzle - PHP"},{"label":"PHP - HTTP_Request2","value":"php - HTTP_Request2 - PHP"},{"label":"PHP - pecl_http","value":"php - pecl_http - PHP"},{"label":"PowerShell - RestMethod","value":"powershell - RestMethod - PowerShell"},{"label":"Python - http.client","value":"python - http.client - Python"},{"label":"Python - Requests","value":"python - Requests - Python"},{"label":"R - httr","value":"r - httr - R"},{"label":"R - RCurl","value":"r - RCurl - R"},{"label":"Ruby - Net::HTTP","value":"ruby - Net::HTTP - Ruby"},{"label":"Shell - Httpie","value":"shell - Httpie - Shell"},{"label":"Shell - wget","value":"shell - wget - Shell"},{"label":"Swift - URLSession","value":"swift - URLSession - Swift"}],"layoutOptions":[{"value":"classic-single-column","label":"Single Column"},{"value":"classic-double-column","label":"Double Column"}],"versionOptions":[],"environmentOptions":[{"value":"0","label":"No Environment"}],"canonicalUrl":"https://documenter.gw.postman.com/view/metadata/2sA3XY7J6K"}