class ChaCha20 extends Salsa20 (View source)

Pure-PHP implementation of ChaCha20.

Constants

MODE_CTR

Encrypt / decrypt using the Counter mode.

Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.

MODE_ECB

Encrypt / decrypt using the Electronic Code Book mode.

MODE_CBC

Encrypt / decrypt using the Code Book Chaining mode.

MODE_CFB

Encrypt / decrypt using the Cipher Feedback mode.

MODE_CFB8

Encrypt / decrypt using the Cipher Feedback mode (8bit)

MODE_OFB

Encrypt / decrypt using the Output Feedback mode.

MODE_GCM

Encrypt / decrypt using Galois/Counter mode.

MODE_STREAM

Encrypt / decrypt using streaming mode.

MODE_MAP

Mode Map

ENGINE_INTERNAL

Base value for the internal implementation $engine switch

ENGINE_EVAL

Base value for the eval() implementation $engine switch

ENGINE_MCRYPT

Base value for the mcrypt implementation $engine switch

ENGINE_OPENSSL

Base value for the openssl implementation $engine switch

ENGINE_LIBSODIUM

Base value for the libsodium implementation $engine switch

ENGINE_OPENSSL_GCM

Base value for the openssl / gcm implementation $engine switch

ENGINE_MAP

Engine Reverse Map

ENCRYPT

DECRYPT

Properties

protected int $mode The Encryption Mode from  SymmetricKey
protected int $block_size Block Length of the cipher from  StreamCipher
protected string $key The Key from  SymmetricKey
protected string $iv The Initialization Vector from  SymmetricKey
protected string $encryptIV A "sliding" Initialization Vector from  SymmetricKey
protected string $decryptIV A "sliding" Initialization Vector from  SymmetricKey
protected bool $continuousBuffer Continuous Buffer status from  SymmetricKey
protected array $enbuffer Encryption buffer for continuous mode from  Salsa20
protected array $debuffer Decryption buffer for continuous mode from  Salsa20
protected int $cfb_init_len Optimizing value while CFB-encrypting from  SymmetricKey
protected bool $changed Does internal cipher state need to be (re)initialized? from  SymmetricKey
protected bool $nonIVChanged Does Eval engie need to be (re)initialized? from  SymmetricKey
protected int $engine Holds which crypt engine internaly should be use, which will be determined automatically on __construct() from  SymmetricKey
protected string $cipher_name_mcrypt The mcrypt specific name of the cipher from  SymmetricKey
protected string $cipher_name_openssl The OpenSSL specific name of the cipher
protected string $cipher_name_openssl_ecb The openssl specific name of the cipher in ECB mode from  SymmetricKey
protected callable $inline_crypt The name of the performance-optimized callback function from  SymmetricKey
protected bool $explicit_key_length Has the key length explicitly been set or should it be derived from the key, itself? from  SymmetricKey
protected string $aad Additional authenticated data from  SymmetricKey
protected string $newtag Authentication Tag produced after a round of encryption from  SymmetricKey
protected string $oldtag Authentication Tag to be verified during decryption from  SymmetricKey
protected string $poly1305Key Poly1305 Key from  SymmetricKey
protected bool $usePoly1305 Poly1305 Flag from  SymmetricKey
protected string $nonce Nonce from  SymmetricKey
protected string|false $p1 Part 1 of the state from  Salsa20
protected string|false $p2 Part 2 of the state from  Salsa20
protected int $key_length Key Length (in bytes) from  Salsa20
protected int $counter Counter from  Salsa20
protected bool $usingGeneratedPoly1305Key Using Generated Poly1305 Key from  Salsa20

Methods

__construct()

Default Constructor.

setIV(string $iv)

Sets the initialization vector.

enablePoly1305()

Enables Poly1305 mode.

setPoly1305Key(string $key = null)

Enables Poly1305 mode.

setNonce(string $nonce)

Sets the nonce.

setAAD(string $aad)

Sets additional authenticated data

bool
usesIV()

Stream ciphers not use an IV

bool
usesNonce()

Salsa20 uses a nonce

from  Salsa20
int
getKeyLength()

Returns the current key length in bits

int
getBlockLength()

Returns the current block length in bits

int
getBlockLengthInBytes()

Returns the current block length in bytes

setKeyLength(int $length)

Sets the key length.

setKey(string $key)

Sets the key.

from  Salsa20
bool
setPassword(string $password, string $method = 'pbkdf2', string[] ...$func_args)

Sets the password.

string
encrypt(string $plaintext)

Encrypts a message.

string
decrypt(string $ciphertext)

Decrypts a message.

string
getTag(int $length = 16)

Get the authentication tag

setTag(string $tag)

Sets the authentication tag

string
getIV(string $iv)

Get the IV

string
openssl_translate_mode()

phpseclib <-> OpenSSL Mode Mapper

enablePadding()

Pad "packets".

disablePadding()

Do not pad packets.

enableContinuousBuffer()

Treat consecutive "packets" as if they are a continuous buffer.

disableContinuousBuffer()

Treat consecutive packets as if they are a discontinuous buffer.

bool
isValidEngineHelper(int $engine)

Test for engine validity

bool
isValidEngine(string $engine)

Test for engine validity

setPreferredEngine(string $engine)

Sets the preferred crypt engine

getEngine()

Returns the engine currently being utilized

setEngine()

Sets the engine as appropriate

string
encryptBlock(string $in)

Encrypts a block

from  Salsa20
string
decryptBlock(string $in)

Decrypts a block

from  Salsa20
setupKey()

Setup the key (expansion)

from  Salsa20
setup()

Setup the self::ENGINE_INTERNAL $engine

string
pad(string $text)

Pads a string

string
unpad(string $text)

Unpads a string.

string
createInlineCryptFunction(array $cipher_code)

Creates the performance-optimized function for en/decrypt()

static int
safe_intval(string $x)

Convert float to int

static string
safe_intval_inline()

eval()'able string for in-line float to int

static string
nullPad128(string $str)

NULL pads a string to be a multiple of 128

string
poly1305(string $ciphertext)

Calculates Poly1305 MAC

from  Salsa20
setCounter(int $counter)

Sets the counter.

from  Salsa20
createPoly1305Key()

Creates a Poly1305 key using the method discussed in RFC8439

from  Salsa20
static int
leftRotate(int $x, int $n)

Left Rotate

from  Salsa20
static 
quarterRound(int $a, int $b, int $c, int $d)

The quarterround function

static 
doubleRound(int $x0, int $x1, int $x2, int $x3, int $x4, int $x5, int $x6, int $x7, int $x8, int $x9, int $x10, int $x11, int $x12, int $x13, int $x14, int $x15)

The doubleround function

static 
salsa20(string $x)

The Salsa20 hash function function

Details

__construct()

Default Constructor.

setIV(string $iv)

Sets the initialization vector.

setIV() is not required when ecb or gcm modes are being used.

{@internal Can be overwritten by a sub class, but does not have to be}

Parameters

string $iv

Exceptions

LengthException if the IV length isn't equal to the block size
BadMethodCallException if an IV is provided when one shouldn't be

enablePoly1305()

Enables Poly1305 mode.

Once enabled Poly1305 cannot be disabled.

Exceptions

BadMethodCallException if Poly1305 is enabled whilst in GCM mode

setPoly1305Key(string $key = null)

Enables Poly1305 mode.

Once enabled Poly1305 cannot be disabled. If $key is not passed then an attempt to call createPoly1305Key will be made.

Parameters

string $key optional

Exceptions

LengthException if the key isn't long enough
BadMethodCallException if Poly1305 is enabled whilst in GCM mode

setNonce(string $nonce)

Sets the nonce.

Parameters

string $nonce

setAAD(string $aad)

Sets additional authenticated data

setAAD() is only used by gcm or in poly1305 mode

Parameters

string $aad

Exceptions

BadMethodCallException if mode isn't GCM or if poly1305 isn't being utilized

bool usesIV()

Stream ciphers not use an IV

Return Value

bool

bool usesNonce()

Salsa20 uses a nonce

Return Value

bool

int getKeyLength()

Returns the current key length in bits

Return Value

int

int getBlockLength()

Returns the current block length in bits

Return Value

int

int getBlockLengthInBytes()

Returns the current block length in bytes

Return Value

int

setKeyLength(int $length)

Sets the key length.

Keys with explicitly set lengths need to be treated accordingly

Parameters

int $length

setKey(string $key)

Sets the key.

Parameters

string $key

Exceptions

LengthException if the key length isn't supported

bool setPassword(string $password, string $method = 'pbkdf2', string[] ...$func_args)

Sets the password.

Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1: $hash, $salt, $count, $dkLen

    Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php

{@internal Could, but not must, extend by the child Crypt_* class}

Parameters

string $password
string $method
string[] ...$func_args

Return Value

bool

Exceptions

LengthException if pbkdf1 is being used and the derived key length exceeds the hash length

See also

r y

string encrypt(string $plaintext)

Encrypts a message.

Parameters

string $plaintext

Return Value

string $ciphertext

See also

SymmetricKey::decrypt
\self::crypt()

string decrypt(string $ciphertext)

Decrypts a message.

$this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). At least if the continuous buffer is disabled.

Parameters

string $ciphertext

Return Value

string $plaintext

See also

SymmetricKey::encrypt
\self::crypt()

string getTag(int $length = 16)

Get the authentication tag

Only used in GCM or Poly1305 mode

Parameters

int $length optional

Return Value

string

Exceptions

LengthException if $length isn't of a sufficient length
RuntimeException if GCM mode isn't being used

See also

\self::encrypt()

setTag(string $tag)

Sets the authentication tag

Only used in GCM mode

Parameters

string $tag

Exceptions

LengthException if $length isn't of a sufficient length
RuntimeException if GCM mode isn't being used

See also

\self::decrypt()

protected string getIV(string $iv)

Get the IV

mcrypt requires an IV even if ECB is used

Parameters

string $iv

Return Value

string

See also

\self::encrypt()
\self::decrypt()

protected string openssl_translate_mode()

phpseclib <-> OpenSSL Mode Mapper

May need to be overwritten by classes extending this one in some cases

Return Value

string

enablePadding()

Pad "packets".

Block ciphers working by encrypting between their specified [$this->]block_size at a time If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to pad the input so that it is of the proper length.

Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH, where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is transmitted separately)

See also

\self::disablePadding()

disablePadding()

Do not pad packets.

See also

\self::enablePadding()

enableContinuousBuffer()

Treat consecutive "packets" as if they are a continuous buffer.

Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets will yield different outputs:

echo $rijndael->encrypt(substr($plaintext, 0, 16)); echo $rijndael->encrypt(substr($plaintext, 16, 16)); echo $rijndael->encrypt($plaintext);

The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates another, as demonstrated with the following:

$rijndael->encrypt(substr($plaintext, 0, 16)); echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16))); echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));

With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different outputs. The reason is due to the fact that the initialization vector's change after every encryption / decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.

Put another way, when the continuous buffer is enabled, the state of the \phpseclib3\Crypt*() object changes after each encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), however, they are also less intuitive and more likely to cause you problems.

{@internal Could, but not must, extend by the child Crypt_* class}

See also

\self::disableContinuousBuffer()

disableContinuousBuffer()

Treat consecutive packets as if they are a discontinuous buffer.

The default behavior.

{@internal Could, but not must, extend by the child Crypt_* class}

See also

\self::enableContinuousBuffer()

protected bool isValidEngineHelper(int $engine)

Test for engine validity

This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()

Parameters

int $engine

Return Value

bool

See also

SymmetricKey::__construct

bool isValidEngine(string $engine)

Test for engine validity

Parameters

string $engine

Return Value

bool

See also

\self::__construct()

setPreferredEngine(string $engine)

Sets the preferred crypt engine

Currently, $engine could be:

  • libsodium[very fast]

  • OpenSSL [very fast]

  • mcrypt [fast]

  • Eval [slow]

  • PHP [slowest]

If the preferred crypt engine is not available the fastest available one will be used

Parameters

string $engine

See also

\self::__construct()

getEngine()

Returns the engine currently being utilized

See also

\self::setEngine()

protected setEngine()

Sets the engine as appropriate

See also

\self::__construct()

protected string encryptBlock(string $in)

Encrypts a block

Parameters

string $in

Return Value

string

protected string decryptBlock(string $in)

Decrypts a block

Parameters

string $in

Return Value

string

protected setupKey()

Setup the key (expansion)

protected setup()

Setup the self::ENGINE_INTERNAL $engine

(re)init, if necessary, the internal cipher $engine

_setup() will be called each time if $changed === true typically this happens when using one or more of following public methods:

  • setKey()

  • setNonce()

  • First run of encrypt() / decrypt() with no init-settings

See also

\self::setKey()
\self::setNonce()
\self::disableContinuousBuffer()

protected string pad(string $text)

Pads a string

Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize. $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to chr($this->block_size - (strlen($text) % $this->block_size)

If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless and padding will, hence forth, be enabled.

Parameters

string $text

Return Value

string

Exceptions

LengthException if padding is disabled and the plaintext's length is not a multiple of the block size

See also

\self::unpad()

protected string unpad(string $text)

Unpads a string.

If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong and false will be returned.

Parameters

string $text

Return Value

string

Exceptions

LengthException if the ciphertext's length is not a multiple of the block size

See also

\self::pad()

protected string createInlineCryptFunction(array $cipher_code)

Creates the performance-optimized function for en/decrypt()

Internally for phpseclib developers:

_createInlineCryptFunction():

  • merge the $cipher_code [setup'ed by _setupInlineCrypt()] with the current [$this->]mode of operation code

  • create the $inline function, which called by encrypt() / decrypt() as its replacement to speed up the en/decryption operations.

  • return the name of the created $inline callback function

  • used to speed up en/decryption

The main reason why can speed up things [up to 50%] this way are:

  • using variables more effective then regular. (ie no use of expensive arrays but integers $k_0, $k_1 ... or even, for example, the pure $key[] values hardcoded)

  • avoiding 1000's of function calls of ie _encryptBlock() but inlining the crypt operations. in the mode of operation for() loop.

  • full loop unroll the (sometimes key-dependent) rounds avoiding this way ++$i counters and runtime-if's etc...

The basic code architectur of the generated $inline en/decrypt() lambda function, in pseudo php, is:

+----------------------------------------------------------------------------------------------+ | callback $inline = create_function: | | lambda_function_0001_crypt_ECB($action, $text) | | { | | INSERT PHP CODE OF: | | $cipher_code['init_crypt']; // general init code. | | // ie: $sbox'es declarations used for | | // encrypt and decrypt'ing. | | | | switch ($action) { | | case 'encrypt': | | INSERT PHP CODE OF: | | $cipher_code['init_encrypt']; // encrypt sepcific init code. | | ie: specified $key or $box | | declarations for encrypt'ing. | | | | foreach ($ciphertext) { | | $in = $block_size of $ciphertext; | | | | INSERT PHP CODE OF: | | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: | | // strlen($in) == $this->block_size | | // here comes the cipher algorithm in action | | // for encryption. | | // $cipher_code['encrypt_block'] has to | | // encrypt the content of the $in variable | | | | $plaintext .= $in; | | } | | return $plaintext; | | | | case 'decrypt': | | INSERT PHP CODE OF: | | $cipher_code['init_decrypt']; // decrypt sepcific init code | | ie: specified $key or $box | | declarations for decrypt'ing. | | foreach ($plaintext) { | | $in = $block_size of $plaintext; | | | | INSERT PHP CODE OF: | | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always | | // strlen($in) == $this->block_size | | // here comes the cipher algorithm in action | | // for decryption. | | // $cipher_code['decrypt_block'] has to | | // decrypt the content of the $in variable | | $ciphertext .= $in; | | } | | return $ciphertext; | | } | | } | +----------------------------------------------------------------------------------------------+

See also the \phpseclib3\Crypt*::_setupInlineCrypt()'s for productive inline $cipher_code's how they works.

Structure of: $cipher_code = [ 'init_crypt' => (string) '', // optional 'init_encrypt' => (string) '', // optional 'init_decrypt' => (string) '', // optional 'encrypt_block' => (string) '', // required 'decrypt_block' => (string) '' // required ];

Parameters

array $cipher_code

Return Value

string (the name of the created callback function)

See also

\self::setupInlineCrypt()
\self::encrypt()
\self::decrypt()

static protected int safe_intval(string $x)

Convert float to int

On ARM CPUs converting floats to ints doesn't always work

Parameters

string $x

Return Value

int

static protected string safe_intval_inline()

eval()'able string for in-line float to int

Return Value

string

static protected string nullPad128(string $str)

NULL pads a string to be a multiple of 128

Parameters

string $str

Return Value

string

See also

\self::decrypt()
\self::encrypt()
\self::setupGCM()

protected string poly1305(string $ciphertext)

Calculates Poly1305 MAC

Parameters

string $ciphertext

Return Value

string

See also

\self::decrypt()
\self::encrypt()

setCounter(int $counter)

Sets the counter.

Parameters

int $counter

protected createPoly1305Key()

Creates a Poly1305 key using the method discussed in RFC8439

See https://tools.ietf.org/html/rfc8439#section-2.6.1

static protected int leftRotate(int $x, int $n)

Left Rotate

Parameters

int $x
int $n

Return Value

int

static protected quarterRound(int $a, int $b, int $c, int $d)

The quarterround function

Parameters

int $a
int $b
int $c
int $d

static protected doubleRound(int $x0, int $x1, int $x2, int $x3, int $x4, int $x5, int $x6, int $x7, int $x8, int $x9, int $x10, int $x11, int $x12, int $x13, int $x14, int $x15)

The doubleround function

Parameters

int $x0 (by reference)
int $x1 (by reference)
int $x2 (by reference)
int $x3 (by reference)
int $x4 (by reference)
int $x5 (by reference)
int $x6 (by reference)
int $x7 (by reference)
int $x8 (by reference)
int $x9 (by reference)
int $x10 (by reference)
int $x11 (by reference)
int $x12 (by reference)
int $x13 (by reference)
int $x14 (by reference)
int $x15 (by reference)

static protected salsa20(string $x)

The Salsa20 hash function function

On my laptop this loop unrolled / function dereferenced version of parent::salsa20 encrypts 1mb of text in 0.65s vs the 0.85s that it takes with the parent method.

If we were free to assume that the host OS would always be 64-bits then the if condition in leftRotate could be eliminated and we could knock this done to 0.60s.

For comparison purposes, RC4 takes 0.16s and AES in CTR mode with the Eval engine takes 0.48s. AES in CTR mode with the PHP engine takes 1.19s. Salsa20 / ChaCha20 do not benefit as much from the Eval approach due to the fact that there are a lot less variables to de-reference, fewer loops to unroll, etc

Parameters

string $x