Skip to content

Commit 9df902a

Browse files
committed
Fix AES256 encryption bug requiring initialization vector (IV)
1 parent ac5c98c commit 9df902a

File tree

4 files changed

+35
-9
lines changed

4 files changed

+35
-9
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
All notable changes to `laravel-netopia-payments` will be documented in this file.
44

5+
## 0.0.2 - 2025-05-25
6+
7+
- Fixed bug with AES256 encryption requiring an initialization vector (IV)
8+
- Updated controller to handle the IV parameter in payment processing
9+
510
## 0.0.1 - 2025-05-25
611

712
- Initial release

src/Http/Controllers/NetopiaPaymentController.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,13 @@ class NetopiaPaymentController extends Controller
2222
public function confirm(Request $request)
2323
{
2424
try {
25-
// Get the env_key and data from the request
25+
// Get the env_key, data and iv from the request
2626
$envKey = $request->input('env_key');
2727
$data = $request->input('data');
28+
$iv = $request->input('iv');
2829

2930
// Process the payment response
30-
$response = NetopiaPayments::processResponse($envKey, $data);
31+
$response = NetopiaPayments::processResponse($envKey, $data, $iv);
3132

3233
// Log the payment response
3334
Log::info('Netopia payment response', [
@@ -76,12 +77,13 @@ public function confirm(Request $request)
7677
public function return(Request $request)
7778
{
7879
try {
79-
// Get the env_key and data from the request
80+
// Get the env_key, data and iv from the request
8081
$envKey = $request->input('env_key');
8182
$data = $request->input('data');
83+
$iv = $request->input('iv');
8284

8385
// Process the payment response
84-
$response = NetopiaPayments::processResponse($envKey, $data);
86+
$response = NetopiaPayments::processResponse($envKey, $data, $iv);
8587

8688
// Redirect based on the payment status
8789
if ($response->isSuccessful() || $response->isPaid()) {

src/NetopiaPayments.php

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,12 @@ protected function encrypt(string $data)
207207
// Encrypt the data
208208
$encryptedData = '';
209209
$envKeys = [];
210-
if (!openssl_seal($data, $encryptedData, $envKeys, [$publicKey], 'AES256')) {
210+
$iv = '';
211+
// Generate a random IV for AES256 cipher
212+
$ivLength = openssl_cipher_iv_length('AES256');
213+
$iv = openssl_random_pseudo_bytes($ivLength);
214+
215+
if (!openssl_seal($data, $encryptedData, $envKeys, [$publicKey], 'AES256', $iv)) {
211216
throw new Exception('Could not encrypt data');
212217
}
213218

@@ -218,6 +223,7 @@ protected function encrypt(string $data)
218223
return [
219224
'env_key' => base64_encode($envKeys[0]),
220225
'data' => base64_encode($encryptedData),
226+
'iv' => base64_encode($iv),
221227
];
222228
}
223229

@@ -226,14 +232,18 @@ protected function encrypt(string $data)
226232
*
227233
* @param string $envKey
228234
* @param string $data
235+
* @param string|null $iv
229236
* @return string
230237
* @throws Exception
231238
*/
232-
protected function decrypt(string $envKey, string $data)
239+
protected function decrypt(string $envKey, string $data, string $iv = null)
233240
{
234241
// Decode the data
235242
$envKey = base64_decode($envKey);
236243
$data = base64_decode($data);
244+
if ($iv !== null) {
245+
$iv = base64_decode($iv);
246+
}
237247

238248
// Read the private key
239249
$privateKey = openssl_pkey_get_private(file_get_contents($this->privateKeyPath));
@@ -243,7 +253,7 @@ protected function decrypt(string $envKey, string $data)
243253

244254
// Decrypt the data
245255
$decryptedData = '';
246-
if (!openssl_open($data, $decryptedData, $envKey, $privateKey, 'AES256')) {
256+
if (!openssl_open($data, $decryptedData, $envKey, $privateKey, 'AES256', $iv)) {
247257
throw new Exception('Could not decrypt data');
248258
}
249259

@@ -259,13 +269,14 @@ protected function decrypt(string $envKey, string $data)
259269
*
260270
* @param string $envKey
261271
* @param string $data
272+
* @param string|null $iv
262273
* @return Response
263274
* @throws Exception
264275
*/
265-
public function processResponse(string $envKey, string $data)
276+
public function processResponse(string $envKey, string $data, string $iv = null)
266277
{
267278
// Decrypt the data
268-
$decryptedData = $this->decrypt($envKey, $data);
279+
$decryptedData = $this->decrypt($envKey, $data, $iv);
269280

270281
// Parse the XML
271282
$xmlDoc = new DOMDocument();

tests/Feature/NetopiaPaymentControllerTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// Mock the NetopiaPayments facade
1818
NetopiaPayments::shouldReceive('processResponse')
1919
->once()
20+
->with('test-env-key', 'test-data', 'test-iv')
2021
->andReturn(createSuccessfulResponse());
2122

2223
NetopiaPayments::shouldReceive('generatePaymentResponse')
@@ -30,6 +31,7 @@
3031
$request = Request::create('/netopia/confirm', 'POST', [
3132
'env_key' => 'test-env-key',
3233
'data' => 'test-data',
34+
'iv' => 'test-iv',
3335
]);
3436

3537
// Call the controller method
@@ -47,6 +49,7 @@
4749
// Mock the NetopiaPayments facade
4850
NetopiaPayments::shouldReceive('processResponse')
4951
->once()
52+
->with('test-env-key', 'test-data', 'test-iv')
5053
->andReturn(createPendingResponse());
5154

5255
NetopiaPayments::shouldReceive('generatePaymentResponse')
@@ -60,6 +63,7 @@
6063
$request = Request::create('/netopia/confirm', 'POST', [
6164
'env_key' => 'test-env-key',
6265
'data' => 'test-data',
66+
'iv' => 'test-iv',
6367
]);
6468

6569
// Call the controller method
@@ -77,6 +81,7 @@
7781
// Mock the NetopiaPayments facade
7882
NetopiaPayments::shouldReceive('processResponse')
7983
->once()
84+
->with('test-env-key', 'test-data', 'test-iv')
8085
->andReturn(createCanceledResponse());
8186

8287
NetopiaPayments::shouldReceive('generatePaymentResponse')
@@ -90,6 +95,7 @@
9095
$request = Request::create('/netopia/confirm', 'POST', [
9196
'env_key' => 'test-env-key',
9297
'data' => 'test-data',
98+
'iv' => 'test-iv',
9399
]);
94100

95101
// Call the controller method
@@ -107,6 +113,7 @@
107113
// Mock the NetopiaPayments facade
108114
NetopiaPayments::shouldReceive('processResponse')
109115
->once()
116+
->with('test-env-key', 'test-data', 'test-iv')
110117
->andThrow(new Exception('Test error'));
111118

112119
NetopiaPayments::shouldReceive('generatePaymentResponse')
@@ -117,6 +124,7 @@
117124
$request = Request::create('/netopia/confirm', 'POST', [
118125
'env_key' => 'test-env-key',
119126
'data' => 'test-data',
127+
'iv' => 'test-iv',
120128
]);
121129

122130
// Call the controller method

0 commit comments

Comments
 (0)