wp/wp-includes/sodium_compat/src/Core/ChaCha20.php
changeset 9 177826044cd9
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
       
     1 <?php
       
     2 
       
     3 if (class_exists('ParagonIE_Sodium_Core_ChaCha20', false)) {
       
     4     return;
       
     5 }
       
     6 
       
     7 /**
       
     8  * Class ParagonIE_Sodium_Core_ChaCha20
       
     9  */
       
    10 class ParagonIE_Sodium_Core_ChaCha20 extends ParagonIE_Sodium_Core_Util
       
    11 {
       
    12     /**
       
    13      * Bitwise left rotation
       
    14      *
       
    15      * @internal You should not use this directly from another application
       
    16      *
       
    17      * @param int $v
       
    18      * @param int $n
       
    19      * @return int
       
    20      */
       
    21     public static function rotate($v, $n)
       
    22     {
       
    23         $v &= 0xffffffff;
       
    24         $n &= 31;
       
    25         return (int) (
       
    26             0xffffffff & (
       
    27                 ($v << $n)
       
    28                     |
       
    29                 ($v >> (32 - $n))
       
    30             )
       
    31         );
       
    32     }
       
    33 
       
    34     /**
       
    35      * The ChaCha20 quarter round function. Works on four 32-bit integers.
       
    36      *
       
    37      * @internal You should not use this directly from another application
       
    38      *
       
    39      * @param int $a
       
    40      * @param int $b
       
    41      * @param int $c
       
    42      * @param int $d
       
    43      * @return array<int, int>
       
    44      */
       
    45     protected static function quarterRound($a, $b, $c, $d)
       
    46     {
       
    47         # a = PLUS(a,b); d = ROTATE(XOR(d,a),16);
       
    48         /** @var int $a */
       
    49         $a = ($a + $b) & 0xffffffff;
       
    50         $d = self::rotate($d ^ $a, 16);
       
    51 
       
    52         # c = PLUS(c,d); b = ROTATE(XOR(b,c),12);
       
    53         /** @var int $c */
       
    54         $c = ($c + $d) & 0xffffffff;
       
    55         $b = self::rotate($b ^ $c, 12);
       
    56 
       
    57         # a = PLUS(a,b); d = ROTATE(XOR(d,a), 8);
       
    58         /** @var int $a */
       
    59         $a = ($a + $b) & 0xffffffff;
       
    60         $d = self::rotate($d ^ $a, 8);
       
    61 
       
    62         # c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
       
    63         /** @var int $c */
       
    64         $c = ($c + $d) & 0xffffffff;
       
    65         $b = self::rotate($b ^ $c, 7);
       
    66         return array((int) $a, (int) $b, (int) $c, (int) $d);
       
    67     }
       
    68 
       
    69     /**
       
    70      * @internal You should not use this directly from another application
       
    71      *
       
    72      * @param ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx
       
    73      * @param string $message
       
    74      *
       
    75      * @return string
       
    76      * @throws TypeError
       
    77      * @throws SodiumException
       
    78      */
       
    79     public static function encryptBytes(
       
    80         ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx,
       
    81         $message = ''
       
    82     ) {
       
    83         $bytes = self::strlen($message);
       
    84 
       
    85         /*
       
    86         j0 = ctx->input[0];
       
    87         j1 = ctx->input[1];
       
    88         j2 = ctx->input[2];
       
    89         j3 = ctx->input[3];
       
    90         j4 = ctx->input[4];
       
    91         j5 = ctx->input[5];
       
    92         j6 = ctx->input[6];
       
    93         j7 = ctx->input[7];
       
    94         j8 = ctx->input[8];
       
    95         j9 = ctx->input[9];
       
    96         j10 = ctx->input[10];
       
    97         j11 = ctx->input[11];
       
    98         j12 = ctx->input[12];
       
    99         j13 = ctx->input[13];
       
   100         j14 = ctx->input[14];
       
   101         j15 = ctx->input[15];
       
   102         */
       
   103         $j0  = (int) $ctx[0];
       
   104         $j1  = (int) $ctx[1];
       
   105         $j2  = (int) $ctx[2];
       
   106         $j3  = (int) $ctx[3];
       
   107         $j4  = (int) $ctx[4];
       
   108         $j5  = (int) $ctx[5];
       
   109         $j6  = (int) $ctx[6];
       
   110         $j7  = (int) $ctx[7];
       
   111         $j8  = (int) $ctx[8];
       
   112         $j9  = (int) $ctx[9];
       
   113         $j10 = (int) $ctx[10];
       
   114         $j11 = (int) $ctx[11];
       
   115         $j12 = (int) $ctx[12];
       
   116         $j13 = (int) $ctx[13];
       
   117         $j14 = (int) $ctx[14];
       
   118         $j15 = (int) $ctx[15];
       
   119 
       
   120         $c = '';
       
   121         for (;;) {
       
   122             if ($bytes < 64) {
       
   123                 $message .= str_repeat("\x00", 64 - $bytes);
       
   124             }
       
   125 
       
   126             $x0 =  (int) $j0;
       
   127             $x1 =  (int) $j1;
       
   128             $x2 =  (int) $j2;
       
   129             $x3 =  (int) $j3;
       
   130             $x4 =  (int) $j4;
       
   131             $x5 =  (int) $j5;
       
   132             $x6 =  (int) $j6;
       
   133             $x7 =  (int) $j7;
       
   134             $x8 =  (int) $j8;
       
   135             $x9 =  (int) $j9;
       
   136             $x10 = (int) $j10;
       
   137             $x11 = (int) $j11;
       
   138             $x12 = (int) $j12;
       
   139             $x13 = (int) $j13;
       
   140             $x14 = (int) $j14;
       
   141             $x15 = (int) $j15;
       
   142 
       
   143             # for (i = 20; i > 0; i -= 2) {
       
   144             for ($i = 20; $i > 0; $i -= 2) {
       
   145                 # QUARTERROUND( x0,  x4,  x8,  x12)
       
   146                 list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12);
       
   147 
       
   148                 # QUARTERROUND( x1,  x5,  x9,  x13)
       
   149                 list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13);
       
   150 
       
   151                 # QUARTERROUND( x2,  x6,  x10,  x14)
       
   152                 list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14);
       
   153 
       
   154                 # QUARTERROUND( x3,  x7,  x11,  x15)
       
   155                 list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15);
       
   156 
       
   157                 # QUARTERROUND( x0,  x5,  x10,  x15)
       
   158                 list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15);
       
   159 
       
   160                 # QUARTERROUND( x1,  x6,  x11,  x12)
       
   161                 list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12);
       
   162 
       
   163                 # QUARTERROUND( x2,  x7,  x8,  x13)
       
   164                 list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13);
       
   165 
       
   166                 # QUARTERROUND( x3,  x4,  x9,  x14)
       
   167                 list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14);
       
   168             }
       
   169             /*
       
   170             x0 = PLUS(x0, j0);
       
   171             x1 = PLUS(x1, j1);
       
   172             x2 = PLUS(x2, j2);
       
   173             x3 = PLUS(x3, j3);
       
   174             x4 = PLUS(x4, j4);
       
   175             x5 = PLUS(x5, j5);
       
   176             x6 = PLUS(x6, j6);
       
   177             x7 = PLUS(x7, j7);
       
   178             x8 = PLUS(x8, j8);
       
   179             x9 = PLUS(x9, j9);
       
   180             x10 = PLUS(x10, j10);
       
   181             x11 = PLUS(x11, j11);
       
   182             x12 = PLUS(x12, j12);
       
   183             x13 = PLUS(x13, j13);
       
   184             x14 = PLUS(x14, j14);
       
   185             x15 = PLUS(x15, j15);
       
   186             */
       
   187             /** @var int $x0 */
       
   188             $x0  = ($x0 & 0xffffffff) + $j0;
       
   189             /** @var int $x1 */
       
   190             $x1  = ($x1 & 0xffffffff) + $j1;
       
   191             /** @var int $x2 */
       
   192             $x2  = ($x2 & 0xffffffff) + $j2;
       
   193             /** @var int $x3 */
       
   194             $x3  = ($x3 & 0xffffffff) + $j3;
       
   195             /** @var int $x4 */
       
   196             $x4  = ($x4 & 0xffffffff) + $j4;
       
   197             /** @var int $x5 */
       
   198             $x5  = ($x5 & 0xffffffff) + $j5;
       
   199             /** @var int $x6 */
       
   200             $x6  = ($x6 & 0xffffffff) + $j6;
       
   201             /** @var int $x7 */
       
   202             $x7  = ($x7 & 0xffffffff) + $j7;
       
   203             /** @var int $x8 */
       
   204             $x8  = ($x8 & 0xffffffff) + $j8;
       
   205             /** @var int $x9 */
       
   206             $x9  = ($x9 & 0xffffffff) + $j9;
       
   207             /** @var int $x10 */
       
   208             $x10 = ($x10 & 0xffffffff) + $j10;
       
   209             /** @var int $x11 */
       
   210             $x11 = ($x11 & 0xffffffff) + $j11;
       
   211             /** @var int $x12 */
       
   212             $x12 = ($x12 & 0xffffffff) + $j12;
       
   213             /** @var int $x13 */
       
   214             $x13 = ($x13 & 0xffffffff) + $j13;
       
   215             /** @var int $x14 */
       
   216             $x14 = ($x14 & 0xffffffff) + $j14;
       
   217             /** @var int $x15 */
       
   218             $x15 = ($x15 & 0xffffffff) + $j15;
       
   219 
       
   220             /*
       
   221             x0 = XOR(x0, LOAD32_LE(m + 0));
       
   222             x1 = XOR(x1, LOAD32_LE(m + 4));
       
   223             x2 = XOR(x2, LOAD32_LE(m + 8));
       
   224             x3 = XOR(x3, LOAD32_LE(m + 12));
       
   225             x4 = XOR(x4, LOAD32_LE(m + 16));
       
   226             x5 = XOR(x5, LOAD32_LE(m + 20));
       
   227             x6 = XOR(x6, LOAD32_LE(m + 24));
       
   228             x7 = XOR(x7, LOAD32_LE(m + 28));
       
   229             x8 = XOR(x8, LOAD32_LE(m + 32));
       
   230             x9 = XOR(x9, LOAD32_LE(m + 36));
       
   231             x10 = XOR(x10, LOAD32_LE(m + 40));
       
   232             x11 = XOR(x11, LOAD32_LE(m + 44));
       
   233             x12 = XOR(x12, LOAD32_LE(m + 48));
       
   234             x13 = XOR(x13, LOAD32_LE(m + 52));
       
   235             x14 = XOR(x14, LOAD32_LE(m + 56));
       
   236             x15 = XOR(x15, LOAD32_LE(m + 60));
       
   237             */
       
   238             $x0  ^= self::load_4(self::substr($message, 0, 4));
       
   239             $x1  ^= self::load_4(self::substr($message, 4, 4));
       
   240             $x2  ^= self::load_4(self::substr($message, 8, 4));
       
   241             $x3  ^= self::load_4(self::substr($message, 12, 4));
       
   242             $x4  ^= self::load_4(self::substr($message, 16, 4));
       
   243             $x5  ^= self::load_4(self::substr($message, 20, 4));
       
   244             $x6  ^= self::load_4(self::substr($message, 24, 4));
       
   245             $x7  ^= self::load_4(self::substr($message, 28, 4));
       
   246             $x8  ^= self::load_4(self::substr($message, 32, 4));
       
   247             $x9  ^= self::load_4(self::substr($message, 36, 4));
       
   248             $x10 ^= self::load_4(self::substr($message, 40, 4));
       
   249             $x11 ^= self::load_4(self::substr($message, 44, 4));
       
   250             $x12 ^= self::load_4(self::substr($message, 48, 4));
       
   251             $x13 ^= self::load_4(self::substr($message, 52, 4));
       
   252             $x14 ^= self::load_4(self::substr($message, 56, 4));
       
   253             $x15 ^= self::load_4(self::substr($message, 60, 4));
       
   254 
       
   255             /*
       
   256                 j12 = PLUSONE(j12);
       
   257                 if (!j12) {
       
   258                     j13 = PLUSONE(j13);
       
   259                 }
       
   260              */
       
   261             ++$j12;
       
   262             if ($j12 & 0xf0000000) {
       
   263                 throw new SodiumException('Overflow');
       
   264             }
       
   265 
       
   266             /*
       
   267             STORE32_LE(c + 0, x0);
       
   268             STORE32_LE(c + 4, x1);
       
   269             STORE32_LE(c + 8, x2);
       
   270             STORE32_LE(c + 12, x3);
       
   271             STORE32_LE(c + 16, x4);
       
   272             STORE32_LE(c + 20, x5);
       
   273             STORE32_LE(c + 24, x6);
       
   274             STORE32_LE(c + 28, x7);
       
   275             STORE32_LE(c + 32, x8);
       
   276             STORE32_LE(c + 36, x9);
       
   277             STORE32_LE(c + 40, x10);
       
   278             STORE32_LE(c + 44, x11);
       
   279             STORE32_LE(c + 48, x12);
       
   280             STORE32_LE(c + 52, x13);
       
   281             STORE32_LE(c + 56, x14);
       
   282             STORE32_LE(c + 60, x15);
       
   283             */
       
   284             $block = self::store32_le((int) ($x0  & 0xffffffff)) .
       
   285                  self::store32_le((int) ($x1  & 0xffffffff)) .
       
   286                  self::store32_le((int) ($x2  & 0xffffffff)) .
       
   287                  self::store32_le((int) ($x3  & 0xffffffff)) .
       
   288                  self::store32_le((int) ($x4  & 0xffffffff)) .
       
   289                  self::store32_le((int) ($x5  & 0xffffffff)) .
       
   290                  self::store32_le((int) ($x6  & 0xffffffff)) .
       
   291                  self::store32_le((int) ($x7  & 0xffffffff)) .
       
   292                  self::store32_le((int) ($x8  & 0xffffffff)) .
       
   293                  self::store32_le((int) ($x9  & 0xffffffff)) .
       
   294                  self::store32_le((int) ($x10 & 0xffffffff)) .
       
   295                  self::store32_le((int) ($x11 & 0xffffffff)) .
       
   296                  self::store32_le((int) ($x12 & 0xffffffff)) .
       
   297                  self::store32_le((int) ($x13 & 0xffffffff)) .
       
   298                  self::store32_le((int) ($x14 & 0xffffffff)) .
       
   299                  self::store32_le((int) ($x15 & 0xffffffff));
       
   300 
       
   301             /* Partial block */
       
   302             if ($bytes < 64) {
       
   303                 $c .= self::substr($block, 0, $bytes);
       
   304                 break;
       
   305             }
       
   306 
       
   307             /* Full block */
       
   308             $c .= $block;
       
   309             $bytes -= 64;
       
   310             if ($bytes <= 0) {
       
   311                 break;
       
   312             }
       
   313             $message = self::substr($message, 64);
       
   314         }
       
   315         /* end for(;;) loop */
       
   316 
       
   317         $ctx[12] = $j12;
       
   318         $ctx[13] = $j13;
       
   319         return $c;
       
   320     }
       
   321 
       
   322     /**
       
   323      * @internal You should not use this directly from another application
       
   324      *
       
   325      * @param int $len
       
   326      * @param string $nonce
       
   327      * @param string $key
       
   328      * @return string
       
   329      * @throws SodiumException
       
   330      * @throws TypeError
       
   331      */
       
   332     public static function stream($len = 64, $nonce = '', $key = '')
       
   333     {
       
   334         return self::encryptBytes(
       
   335             new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce),
       
   336             str_repeat("\x00", $len)
       
   337         );
       
   338     }
       
   339 
       
   340     /**
       
   341      * @internal You should not use this directly from another application
       
   342      *
       
   343      * @param int $len
       
   344      * @param string $nonce
       
   345      * @param string $key
       
   346      * @return string
       
   347      * @throws SodiumException
       
   348      * @throws TypeError
       
   349      */
       
   350     public static function ietfStream($len, $nonce = '', $key = '')
       
   351     {
       
   352         return self::encryptBytes(
       
   353             new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce),
       
   354             str_repeat("\x00", $len)
       
   355         );
       
   356     }
       
   357 
       
   358     /**
       
   359      * @internal You should not use this directly from another application
       
   360      *
       
   361      * @param string $message
       
   362      * @param string $nonce
       
   363      * @param string $key
       
   364      * @param string $ic
       
   365      * @return string
       
   366      * @throws SodiumException
       
   367      * @throws TypeError
       
   368      */
       
   369     public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '')
       
   370     {
       
   371         return self::encryptBytes(
       
   372             new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce, $ic),
       
   373             $message
       
   374         );
       
   375     }
       
   376 
       
   377     /**
       
   378      * @internal You should not use this directly from another application
       
   379      *
       
   380      * @param string $message
       
   381      * @param string $nonce
       
   382      * @param string $key
       
   383      * @param string $ic
       
   384      * @return string
       
   385      * @throws SodiumException
       
   386      * @throws TypeError
       
   387      */
       
   388     public static function streamXorIc($message, $nonce = '', $key = '', $ic = '')
       
   389     {
       
   390         return self::encryptBytes(
       
   391             new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce, $ic),
       
   392             $message
       
   393         );
       
   394     }
       
   395 }