cryptal  latest
Cryptography Abstraction Layer
ChaCha20Openssh.php
1 <?php
2 
4 
14 
26 {
28  protected $header;
29 
31  protected $main;
32 
33  protected $cipher;
34  protected $key;
35 
36  public function __construct(
37  CipherEnum $cipher,
38  ModeEnum $mode,
39  PaddingInterface $padding,
40  $key,
41  $tagLength = self::DEFAULT_TAG_LENGTH
42  ) {
43  if (CipherEnum::CIPHER_CHACHA20_OPENSSH() !== $cipher) {
44  throw new \InvalidArgumentException('Unsupported cipher');
45  }
46 
47  if (!($padding instanceof None)) {
48  throw new \InvalidArgumentException(
49  'ChaCha20 does not need any padding ' .
50  '(hint: use fpoirotte\Cryptal\Padding\None)'
51  );
52  }
53 
54  if (16 !== $tagLength) {
55  throw new \InvalidArgumentException('Invalid tag length');
56  }
57 
58  if (64 !== strlen($key)) {
59  throw new \InvalidArgumentException('Invalid key length');
60  }
61 
62  $this->tagLength = $tagLength;
63  $this->main = new ChaCha20($cipher, $mode, $padding, substr($key, 0, 32), 0);
64  $this->header = new ChaCha20($cipher, $mode, $padding, substr($key, 32), 0);
65  $this->key = $key;
66  $this->cipher = $cipher;
67  }
68 
69  public function encrypt($iv, $data, &$tag = null, $aad = '')
70  {
71  if (strlen($iv) != $this->getIVSize()) {
72  throw new \InvalidArgumentException('Invalid Initialization Vector');
73  }
74 
75  $polyKey = $this->main->basicXcrypt(str_repeat("\x00", 32), $iv, 0);
76  $aad = $this->header->basicXcrypt($aad, $iv, 0);
77  $res = $this->main->basicXcrypt($data, $iv, 1);
78 
79  // @FIXME We should probably use the registry here,
80  // in case a C implementation is available.
81  $tag = Poly1305::mac(
82  MacEnum::MAC_POLY1305(),
83  CipherEnum::CIPHER_CHACHA20(),
84  $polyKey,
85  $aad . $res,
86  '',
87  true
88  );
89  return $res;
90  }
91 
92  public function decrypt($iv, $data, $tag = null, $aad = '')
93  {
94  if (strlen($iv) != $this->getIVSize()) {
95  throw new \InvalidArgumentException('Invalid Initialization Vector');
96  }
97 
98  $aad = $this->header->basicXcrypt($aad, $iv, 0);
99  $polyKey = $this->main->basicXcrypt(str_repeat("\x00", 32), $iv, 0);
100 
101  // @FIXME We should probably use the registry here,
102  // in case a C implementation is available.
103  $outTag = Poly1305::mac(
104  MacEnum::MAC_POLY1305(),
105  CipherEnum::CIPHER_CHACHA20(),
106  $polyKey,
107  $aad . $data,
108  '',
109  true
110  );
111  if ($tag !== $outTag) {
112  throw new \InvalidArgumentException('Invalid tag');
113  }
114 
115  return $this->main->basicXcrypt($data, $iv, 1);
116  }
117 
118  public function getIVSize()
119  {
120  return 8;
121  }
122 }
static mac(MacEnum $macAlgorithm, SubAlgorithmAbstractEnum $innerAlgorithm, $key, $data, $nonce= '', $raw=false)
Definition: AbstractMac.php:15
$tagLength
Tag length in bytes; 16 when AEAD is enabled, 0 otherwise.
Definition: ChaCha20.php:31
__construct(CipherEnum $cipher, ModeEnum $mode, PaddingInterface $padding, $key, $tagLength=self::DEFAULT_TAG_LENGTH)