Skip to content

Commit

Permalink
Updated: new encrypted string format
Browse files Browse the repository at this point in the history
  • Loading branch information
capcom6 committed Jan 17, 2024
1 parent 7c7ba4c commit 24e27ee
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 43 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Here is a simple example of how to send a message using the client:
require 'vendor/autoload.php';

use AndroidSmsGateway\Client;
use AndroidSmsGateway\Encryptor;
use AndroidSmsGateway\EncryptedClient;
use AndroidSmsGateway\Domain\Message;

Expand All @@ -34,7 +35,8 @@ $password = 'your_password';

$client = new Client($login, $password);
// or
// $client = new EncryptedClient('your_passphrase', $login, $password);
// $encryptor = new Encryptor('your_passphrase');
// $client = new EncryptedClient($login, $password, Client::DEFAULT_URL, $httpClient, $encryptor);

$message = new Message('Your message text here.', ['+1234567890']);

Expand All @@ -59,12 +61,11 @@ try {

There are two clients available:

- `Client` is used for sending SMS messages in plain text.
- `EncryptedClient` is used for sending AES encrypted SMS messages. You need to provide the same passphrase in Android app.
- `Client` is used for sending SMS messages in plain text, but can also be used for sending encrypted messages by providing an `Encryptor`.

### Methods

Each client has the following methods:
Client has the following methods:

* `Send(Message $message)`: Send a new SMS message.
* `GetState(string $id)`: Retrieve the state of a previously sent message by its ID.
Expand Down
17 changes: 15 additions & 2 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Client {
protected string $baseUrl;

protected HttpClient $client;
protected ?Encryptor $encryptor;

protected RequestFactoryInterface $requestFactory;
protected StreamFactoryInterface $streamFactory;
Expand All @@ -27,11 +28,13 @@ public function __construct(
string $login,
string $password,
string $serverUrl = self::DEFAULT_URL,
?HttpClient $client = null
?HttpClient $client = null,
?Encryptor $encryptor = null
) {
$this->basicAuth = base64_encode($login . ':' . $password);
$this->baseUrl = $serverUrl;
$this->client = $client ?? HttpClientDiscovery::find();
$this->encryptor = $encryptor;

$this->requestFactory = Psr17FactoryDiscovery::findRequestFactory();
$this->streamFactory = Psr17FactoryDiscovery::findStreamFactory();
Expand All @@ -40,6 +43,10 @@ public function __construct(
public function Send(Message $message): MessageState {
$path = '/message';

if (isset($this->encryptor)) {
$message = $message->Encrypt($this->encryptor);
}

$response = $this->sendRequest(
'POST',
$path,
Expand All @@ -63,7 +70,13 @@ public function GetState(string $id): MessageState {
throw new \RuntimeException('Invalid response');
}

return MessageState::FromObject($response);
$state = MessageState::FromObject($response);

if (isset($this->encryptor)) {
$state = $state->Decrypt($this->encryptor);
}

return $state;
}

/**
Expand Down
32 changes: 0 additions & 32 deletions src/EncryptedClient.php

This file was deleted.

45 changes: 40 additions & 5 deletions src/Encryptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,47 @@

class Encryptor {
protected string $passphrase;
protected int $iterationCount;

/**
* Encryptor constructor.
* @param string $passphrase Passphrase to use for encryption
* @param int $iterationCount Iteration count
*/
public function __construct(
string $passphrase
string $passphrase,
int $iterationCount = 75000
) {
$this->passphrase = $passphrase;
$this->iterationCount = $iterationCount;
}

public function Encrypt(string $data): string {
$salt = $this->generateSalt();
$secretKey = $this->generateSecretKeyFromPassphrase($this->passphrase, $salt);
$secretKey = $this->generateSecretKeyFromPassphrase($this->passphrase, $salt, 32, $this->iterationCount);

return base64_encode($salt) . '.' . openssl_encrypt($data, 'aes-256-cbc', $secretKey, 0, $salt);
return sprintf(
'$aes-256-cbc/pbkdf2-sha1$i=%d$%s$%s',
$this->iterationCount,
base64_encode($salt),
openssl_encrypt($data, 'aes-256-cbc', $secretKey, 0, $salt)
);
}

public function Decrypt(string $data): string {
list($saltBase64, $encryptedBase64) = explode('.', $data, 2);
list($_, $algo, $paramsStr, $saltBase64, $encryptedBase64) = explode('$', $data);

if ($algo !== 'aes-256-cbc/pbkdf2-sha1') {
throw new \RuntimeException('Unsupported algorithm');
}

$params = $this->parseParams($paramsStr);
if (empty($params['i'])) {
throw new \RuntimeException('Missing iteration count');
}

$salt = base64_decode($saltBase64);
$secretKey = $this->generateSecretKeyFromPassphrase($this->passphrase, $salt);
$secretKey = $this->generateSecretKeyFromPassphrase($this->passphrase, $salt, 32, intval($params['i']));

return openssl_decrypt($encryptedBase64, 'aes-256-cbc', $secretKey, 0, $salt);
}
Expand All @@ -39,4 +61,17 @@ protected function generateSecretKeyFromPassphrase(
): string {
return hash_pbkdf2('sha1', $passphrase, $salt, $iterationCount, $keyLength, true);
}

/**
* @return array<string, string>
*/
protected function parseParams(string $params): array {
$keyValuePairs = explode(',', $params);
$result = [];
foreach ($keyValuePairs as $pair) {
list($key, $value) = explode('=', $pair, 2);
$result[$key] = $value;
}
return $result;
}
}

0 comments on commit 24e27ee

Please sign in to comment.