IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Reproduire le fonctionnement de AesCtr::encrypt() de PHP


Sujet :

C#

  1. #1
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 152
    Points : 7 402
    Points
    7 402
    Billets dans le blog
    1
    Par défaut Reproduire le fonctionnement de AesCtr::encrypt() de PHP
    Bonjour,

    Vogue la galère, le suis en train de tenter de consommer des API qui nécessitent que j'envoie le contenu de mes requête chiffré avec une méthode particulière.

    Les exemples fournis montre du code PHP :

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    $data=AesCtr::encrypt($data, 'ApiKeyForUserProjeqtor', 256);

    Seul hic, l'algo standard AES nécessite un salt et un iv... aucun d'entre eux n'est fourni ici.

    J'ai trouvé sur le forum du programme avec lequel je tente de m'interfacer que l'implémentation de l'algo par PHP était non standard.
    https://www.projeqtor.org/fr/forum-f...put-post#31812

    Est-ce que vous avez une idée d'où trouver une telle implémentation en C# ?
    On ne jouit bien que de ce qu’on partage.

  2. #2
    Expert éminent sénior

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 757
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 757
    Points : 10 697
    Points
    10 697
    Billets dans le blog
    21
    Par défaut
    J'ai exactement ça sur mon dépôt Github. J'ai eu à le faire pour un client il y a 4 ans



    Les codes sont normalement compatibles (on peut chiffrer en PHP et utiliser la version C# pour déchiffrer et inversement, et cela marche aussi avec la version Java).

    La partie "compliquée" c'est que si l'algo AES est standard, pour le passage de l'IV, rien n'est prédéfini. Souvent l'IV est passé juste avant le message chiffré.
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  3. #3
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 152
    Points : 7 402
    Points
    7 402
    Billets dans le blog
    1
    Par défaut
    Bonjour François, et merci pour ta réponse rapide

    Je viens de tester ta fonction, et visiblement elle doit faire quelque-chose de différent de celle que le programme PHP utilise.

    En effet, voici ce que j'ai réussi à faire (complètement dégueulasse, mais qui marche) :

    La fonction de chiffrement en C# :
    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
            public static string PHPEncrypt(string key, string data)
            {
                string filePath = @"json.dat";
                using (StreamWriter outputFile = new(filePath))
                {
                    outputFile.Write(data);
                    outputFile.Flush();
                    outputFile.Close();
                }
     
                ProcessStartInfo psi = new("php/php.exe", $"Encrypt/encrypt.php {key}");
                psi.CreateNoWindow = true;
                psi.UseShellExecute = false;
                Process.Start(psi).WaitForExit();
     
                string res;
                using (StreamReader inputFile = new(filePath, Encoding.UTF8))
                {
                    res = inputFile.ReadToEnd();
                    inputFile.Close();
                }
     
                return res;
            }

    Le code PHP exécuté :

    encrypt.php
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    <?
    error_reporting(E_ERROR | E_PARSE);
     
    require_once "aes.class.php";
    require_once "aesctr.class.php";
     
    $filename = 'json.dat';
    $contents = file_get_contents($filename);
    $data = AesCtr::encrypt($contents, $_SERVER['argv'][1], 128);
    file_put_contents($filename, $data);
    ?>

    Et les deux include :

    aes.class.php
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
     
    <?php
    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
    /*  AES implementation in PHP                                                                     */
    /*    (c) Chris Veness 2005-2014 www.movable-type.co.uk/scripts                                   */
    /*    Right of free use is granted for all commercial or non-commercial use under CC-BY licence.  */
    /*    No warranty of any form is offered.                                                         */
    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
    Class Aes
    {
        /**
         * AES Cipher function [§5.1]: encrypt 'input' with Rijndael algorithm
         *
         * @param input message as byte-array (16 bytes)
         * @param w     key schedule as 2D byte-array (Nr+1 x Nb bytes) -
         *              generated from the cipher key by keyExpansion()
         * @return      ciphertext as byte-array (16 bytes)
         */
        public static function cipher($input, $w)
        {
            $Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
            $Nr = count($w) / $Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys
     
            $state = array(); // initialise 4xNb byte-array 'state' with input [§3.4]
            for ($i = 0; $i < 4 * $Nb; $i++) $state[$i % 4][floor($i / 4)] = $input[$i];
     
            $state = self::addRoundKey($state, $w, 0, $Nb);
     
            for ($round = 1; $round < $Nr; $round++) { // apply Nr rounds
                $state = self::subBytes($state, $Nb);
                $state = self::shiftRows($state, $Nb);
                $state = self::mixColumns($state, $Nb);
                $state = self::addRoundKey($state, $w, $round, $Nb);
            }
     
            $state = self::subBytes($state, $Nb);
            $state = self::shiftRows($state, $Nb);
            $state = self::addRoundKey($state, $w, $Nr, $Nb);
     
            $output = array(4 * $Nb); // convert state to 1-d array before returning [§3.4]
            for ($i = 0; $i < 4 * $Nb; $i++) $output[$i] = $state[$i % 4][floor($i / 4)];
            return $output;
        }
     
        /**
         * Xor Round Key into state S [§5.1.4].
         */
        private static function addRoundKey($state, $w, $rnd, $Nb)
        {
            for ($r = 0; $r < 4; $r++) {
                for ($c = 0; $c < $Nb; $c++) $state[$r][$c] ^= $w[$rnd * 4 + $c][$r];
            }
            return $state;
        }
     
        /**
         * Apply SBox to state S [§5.1.1].
         */
        private static function subBytes($s, $Nb)
        {
            for ($r = 0; $r < 4; $r++) {
                for ($c = 0; $c < $Nb; $c++) $s[$r][$c] = self::$sBox[$s[$r][$c]];
            }
            return $s;
        }
     
        /**
         * Shift row r of state S left by r bytes [§5.1.2].
         */
        private static function shiftRows($s, $Nb)
        {
            $t = array(4);
            for ($r = 1; $r < 4; $r++) {
                for ($c = 0; $c < 4; $c++) $t[$c] = $s[$r][($c + $r) % $Nb]; // shift into temp copy
                for ($c = 0; $c < 4; $c++) $s[$r][$c] = $t[$c]; // and copy back
            } // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES):
            return $s; // see fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
        }
     
        /**
         * Combine bytes of each col of state S [§5.1.3].
         */
        private static function mixColumns($s, $Nb)
        {
            for ($c = 0; $c < 4; $c++) {
                $a = array(4); // 'a' is a copy of the current column from 's'
                $b = array(4); // 'b' is a•{02} in GF(2^8)
                for ($i = 0; $i < 4; $i++) {
                    $a[$i] = $s[$i][$c];
                    $b[$i] = $s[$i][$c] & 0x80 ? $s[$i][$c] << 1 ^ 0x011b : $s[$i][$c] << 1;
                }
                // a[n] ^ b[n] is a•{03} in GF(2^8)
                $s[0][$c] = $b[0] ^ $a[1] ^ $b[1] ^ $a[2] ^ $a[3]; // 2*a0 + 3*a1 + a2 + a3
                $s[1][$c] = $a[0] ^ $b[1] ^ $a[2] ^ $b[2] ^ $a[3]; // a0 * 2*a1 + 3*a2 + a3
                $s[2][$c] = $a[0] ^ $a[1] ^ $b[2] ^ $a[3] ^ $b[3]; // a0 + a1 + 2*a2 + 3*a3
                $s[3][$c] = $a[0] ^ $b[0] ^ $a[1] ^ $a[2] ^ $b[3]; // 3*a0 + a1 + a2 + 2*a3
            }
            return $s;
        }
     
        /**
         * Generate Key Schedule from Cipher Key [§5.2].
         *
         * Perform key expansion on cipher key to generate a key schedule.
         *
         * @param  key cipher key byte-array (16 bytes).
         * @return key schedule as 2D byte-array (Nr+1 x Nb bytes).
         */
        public static function keyExpansion($key)
        {
            $Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
            $Nk = count($key) / 4; // key length (in words): 4/6/8 for 128/192/256-bit keys
            $Nr = $Nk + 6; // no of rounds: 10/12/14 for 128/192/256-bit keys
     
            $w = array();
            $temp = array();
     
            for ($i = 0; $i < $Nk; $i++) {
                $r = array($key[4 * $i], $key[4 * $i + 1], $key[4 * $i + 2], $key[4 * $i + 3]);
                $w[$i] = $r;
            }
     
            for ($i = $Nk; $i < ($Nb * ($Nr + 1)); $i++) {
                $w[$i] = array();
                for ($t = 0; $t < 4; $t++) $temp[$t] = $w[$i - 1][$t];
                if ($i % $Nk == 0) {
                    $temp = self::subWord(self::rotWord($temp));
                    for ($t = 0; $t < 4; $t++) $temp[$t] ^= self::$rCon[$i / $Nk][$t];
                } else if ($Nk > 6 && $i % $Nk == 4) {
                    $temp = self::subWord($temp);
                }
                for ($t = 0; $t < 4; $t++) $w[$i][$t] = $w[$i - $Nk][$t] ^ $temp[$t];
            }
            return $w;
        }
     
        /**
         * Apply SBox to 4-byte word w.
         */
        private static function subWord($w)
        {
            for ($i = 0; $i < 4; $i++) $w[$i] = self::$sBox[$w[$i]];
            return $w;
        }
     
        /**
         * Rotate 4-byte word w left by one byte.
         */
        private static function rotWord($w)
        {
            $tmp = $w[0];
            for ($i = 0; $i < 3; $i++) $w[$i] = $w[$i + 1];
            $w[3] = $tmp;
            return $w;
        }
     
        // sBox is pre-computed multiplicative inverse in GF(2^8) used in subBytes and keyExpansion [§5.1.1]
        private static $sBox = array(
            0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
            0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
            0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
            0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
            0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
            0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
            0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
            0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
            0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
            0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
            0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
            0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
            0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
            0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
            0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
            0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
     
        // rCon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [§5.2]
        private static $rCon = array(
            array(0x00, 0x00, 0x00, 0x00),
            array(0x01, 0x00, 0x00, 0x00),
            array(0x02, 0x00, 0x00, 0x00),
            array(0x04, 0x00, 0x00, 0x00),
            array(0x08, 0x00, 0x00, 0x00),
            array(0x10, 0x00, 0x00, 0x00),
            array(0x20, 0x00, 0x00, 0x00),
            array(0x40, 0x00, 0x00, 0x00),
            array(0x80, 0x00, 0x00, 0x00),
            array(0x1b, 0x00, 0x00, 0x00),
            array(0x36, 0x00, 0x00, 0x00));
    }
     
    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

    aesctr.class.php
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
     
    <?php
    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
    /*  AES counter (CTR) mode implementation in PHP                                                  */
    /*    (c) Chris Veness 2005-2014 www.movable-type.co.uk/scripts                                   */
    /*    Right of free use is granted for all commercial or non-commercial use under CC-BY licence.  */
    /*    No warranty of any form is offered.                                                         */
    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
     
    Class AesCtr extends Aes
    {
        /**
         * Encrypt a text using AES encryption in Counter mode of operation
         *  - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
         *
         * Unicode multi-byte character safe
         *
         * @param plaintext source text to be encrypted
         * @param password  the password to use to generate a key
         * @param nBits     number of bits to be used in the key (128, 192, or 256)
         * @return          encrypted text
         */
        public static function encrypt($plaintext, $password, $nBits)
        {
            $blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
            if (!($nBits == 128 || $nBits == 192 || $nBits == 256)) return ''; // standard allows 128/192/256 bit keys
            // note PHP (5) gives us plaintext and password in UTF8 encoding!
     
            // use AES itself to encrypt password to get cipher key (using plain password as source for
            // key expansion) - gives us well encrypted key
            $nBytes = $nBits / 8; // no bytes in key
            $pwBytes = array();
            for ($i = 0; $i < $nBytes; $i++) $pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
            $key = Aes::cipher($pwBytes, Aes::keyExpansion($pwBytes));
            $key = array_merge($key, array_slice($key, 0, $nBytes - 16)); // expand key to 16/24/32 bytes long
     
            // initialise 1st 8 bytes of counter block with nonce (NIST SP800-38A §B.2): [0-1] = millisec,
            // [2-3] = random, [4-7] = seconds, giving guaranteed sub-ms uniqueness up to Feb 2106
            $counterBlock = array();
            $nonce = floor(microtime(true) * 1000); // timestamp: milliseconds since 1-Jan-1970
            $nonceMs = $nonce % 1000;
            $nonceSec = floor($nonce / 1000);
            $nonceRnd = floor(rand(0, 0xffff));
     
            for ($i = 0; $i < 2; $i++) $counterBlock[$i] = self::urs($nonceMs, $i * 8) & 0xff;
            for ($i = 0; $i < 2; $i++) $counterBlock[$i + 2] = self::urs($nonceRnd, $i * 8) & 0xff;
            for ($i = 0; $i < 4; $i++) $counterBlock[$i + 4] = self::urs($nonceSec, $i * 8) & 0xff;
     
            // and convert it to a string to go on the front of the ciphertext
            $ctrTxt = '';
            for ($i = 0; $i < 8; $i++) $ctrTxt .= chr($counterBlock[$i]);
     
            // generate key schedule - an expansion of the key into distinct Key Rounds for each round
            $keySchedule = Aes::keyExpansion($key);
            //print_r($keySchedule);
     
            $blockCount = ceil(strlen($plaintext) / $blockSize);
            $ciphertxt = array(); // ciphertext as array of strings
     
            for ($b = 0; $b < $blockCount; $b++) {
                // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
                // done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB)
                for ($c = 0; $c < 4; $c++) $counterBlock[15 - $c] = self::urs($b, $c * 8) & 0xff;
                for ($c = 0; $c < 4; $c++) $counterBlock[15 - $c - 4] = self::urs($b / 0x100000000, $c * 8);
     
                $cipherCntr = Aes::cipher($counterBlock, $keySchedule); // -- encrypt counter block --
     
                // block size is reduced on final block
                $blockLength = $b < $blockCount - 1 ? $blockSize : (strlen($plaintext) - 1) % $blockSize + 1;
                $cipherByte = array();
     
                for ($i = 0; $i < $blockLength; $i++) { // -- xor plaintext with ciphered counter byte-by-byte --
                    $cipherByte[$i] = $cipherCntr[$i] ^ ord(substr($plaintext, $b * $blockSize + $i, 1));
                    $cipherByte[$i] = chr($cipherByte[$i]);
                }
                $ciphertxt[$b] = implode('', $cipherByte); // escape troublesome characters in ciphertext
            }
     
            // implode is more efficient than repeated string concatenation
            $ciphertext = $ctrTxt . implode('', $ciphertxt);
            $ciphertext = base64_encode($ciphertext);
            return $ciphertext;
        }
     
     
        /**
         * Decrypt a text encrypted by AES in counter mode of operation
         *
         * @param ciphertext source text to be decrypted
         * @param password   the password to use to generate a key
         * @param nBits      number of bits to be used in the key (128, 192, or 256)
         * @return           decrypted text
         */
        public static function decrypt($ciphertext, $password, $nBits)
        {
            $blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
            if (!($nBits == 128 || $nBits == 192 || $nBits == 256)) return ''; // standard allows 128/192/256 bit keys
            $ciphertext = base64_decode($ciphertext);
     
            // use AES to encrypt password (mirroring encrypt routine)
            $nBytes = $nBits / 8; // no bytes in key
            $pwBytes = array();
            for ($i = 0; $i < $nBytes; $i++) $pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
            $key = Aes::cipher($pwBytes, Aes::keyExpansion($pwBytes));
            $key = array_merge($key, array_slice($key, 0, $nBytes - 16)); // expand key to 16/24/32 bytes long
     
            // recover nonce from 1st element of ciphertext
            $counterBlock = array();
            $ctrTxt = substr($ciphertext, 0, 8);
            for ($i = 0; $i < 8; $i++) $counterBlock[$i] = ord(substr($ctrTxt, $i, 1));
     
            // generate key schedule
            $keySchedule = Aes::keyExpansion($key);
     
            // separate ciphertext into blocks (skipping past initial 8 bytes)
            $nBlocks = ceil((strlen($ciphertext) - 8) / $blockSize);
            $ct = array();
            for ($b = 0; $b < $nBlocks; $b++) $ct[$b] = substr($ciphertext, 8 + $b * $blockSize, 16);
            $ciphertext = $ct; // ciphertext is now array of block-length strings
     
            // plaintext will get generated block-by-block into array of block-length strings
            $plaintxt = array();
     
            for ($b = 0; $b < $nBlocks; $b++) {
                // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
                for ($c = 0; $c < 4; $c++) $counterBlock[15 - $c] = self::urs($b, $c * 8) & 0xff;
                for ($c = 0; $c < 4; $c++) $counterBlock[15 - $c - 4] = self::urs(($b + 1) / 0x100000000 - 1, $c * 8) & 0xff;
     
                $cipherCntr = Aes::cipher($counterBlock, $keySchedule); // encrypt counter block
     
                $plaintxtByte = array();
                for ($i = 0; $i < strlen($ciphertext[$b]); $i++) {
                    // -- xor plaintext with ciphered counter byte-by-byte --
                    $plaintxtByte[$i] = $cipherCntr[$i] ^ ord(substr($ciphertext[$b], $i, 1));
                    $plaintxtByte[$i] = chr($plaintxtByte[$i]);
                }
                $plaintxt[$b] = implode('', $plaintxtByte);
            }
     
            // join array of blocks into single plaintext string
            $plaintext = implode('', $plaintxt);
     
            return $plaintext;
        }
     
        /*
         * Unsigned right shift function, since PHP has neither >>> operator nor unsigned ints
         *
         * @param a  number to be shifted (32-bit integer)
         * @param b  number of bits to shift a to the right (0..31)
         * @return   a right-shifted and zero-filled by b bits
         */
        private static function urs($a, $b)
        {
            $a &= 0xffffffff;
            $b &= 0x1f; // (bounds check)
            if ($a & 0x80000000 && $b > 0) { // if left-most bit set
                $a = ($a >> 1) & 0x7fffffff; //   right-shift one bit & clear left-most bit
                $a = $a >> ($b - 1); //   remaining right-shifts
            } else { // otherwise
                $a = ($a >> $b); //   use normal right-shift
            }
            return $a;
        }
    }
     
    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

    Et tout ça, je l'appelle depuis cette méthode :
    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
            public static async Task ChangeUserFiggoId(Common.User user)
            {
     
                string data = $"{{\"id\":\"{user.ProjeqtorId}\", \"figgoId\":\"{user.FiggoId}\"}}";
                string crypted = PHPEncrypt(api_key, data);
                //string crypted = Encrypt.AesCryptography.EncryptWithAes(data, api_key);
     
                client.DefaultRequestHeaders.Clear();
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
                var authToken = Encoding.ASCII.GetBytes($"{login}:{pass}");
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(authToken));
                var content = new StringContent(crypted, Encoding.UTF8, "application/json");
                await client.PutAsync(string.Concat(url, User.PATH), content);
            }

    La solution avec PHP (oui, c'est mal, obligé de déployer php.exe et php8.dll dans bon output, lancer l'interprétation d'un script, travailler dans un fichier temporaire sur le disque... de quoi vomir) fonctionne.

    Par contre quand j'ai voulu mettre ta méthode :

    [inline=csharp]string crypted = Encrypt.AesCryptography.EncryptWithAes(data, api_key);[/inline]

    Avec cette méthode :
    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
            public static string EncryptWithAes(string plainContent, string key)
            {
                return Encoding.UTF8.GetString(EncryptWithAes(Encoding.UTF8.GetBytes(plainContent), Encoding.UTF8.GetBytes(key)));
            }

    Proutch, marche plus
    On ne jouit bien que de ce qu’on partage.

  4. #4
    Expert éminent sénior

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 757
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 757
    Points : 10 697
    Points
    10 697
    Billets dans le blog
    21
    Par défaut
    Ah pardon, j'ai lu trop vite ! Je croyais que tu cherchais une implémentation compatible entre le php et le C#, mais je n'avais pas compris que la partie PHP était "figée". Donc non, effectivement, il y a peu de chance que l'implémentation C# que je t'ai fourni soit compatible avec ta version en PHP...

    Il faudrait regarder le code PHP en détail pour faire l'implémentation exacte en C#... Mais là, vu le code, cela ne se fait pas en 5min
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  5. #5
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 152
    Points : 7 402
    Points
    7 402
    Billets dans le blog
    1
    Par défaut
    Oui, c'est pour ça que j'ai préféré la méthode pourrie qui consiste à appeler la méthode PHP depuis mon programme...
    Au moins j'ai pas besoin de m'embêter à transposer/maintenir le code de chiffrement

    Accessoirement ça marche plutôt bien contre toute attente. Y'a juste le passage par un fichier temporaire qui m'ennuie, mais j'ai pas trop envie de manipuler des redirections de streams de la console, je sens que je vais m'embêter pour rien s'il y a des caractères spéciaux dans les données...
    On ne jouit bien que de ce qu’on partage.

  6. #6
    Expert éminent sénior

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 757
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 757
    Points : 10 697
    Points
    10 697
    Billets dans le blog
    21
    Par défaut
    J'ai creusé un peu, et en fait, c'est vachement compliqué, dans la mesure où le mode Counter (CTR) pour AES n'est pas nativement gérée. En fait, c'est même la première fois que je vois ce mode de communication, les plus courants étant les CBC et ECB.

    Donc bon, pas impossible, mais il faut presque réimplémenter complètement l'algo AES pour ce mode spécifique... (a priori, il est possible d'utiliser le mode ECB et de gérer soi-même le compteur mais c'est quand même un peu de boulot).

    En bref, le choix de cet algo est quand même bancal je trouve, surtout pour un service web ! Cela donne surtout l'impression que le service a été conçu sans tenir compte du fait qu'il pourrait être consommé dans un autre langage...
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  7. #7
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 152
    Points : 7 402
    Points
    7 402
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par François DORIN Voir le message
    Cela donne surtout l'impression que le service a été conçu sans tenir compte du fait qu'il pourrait être consommé dans un autre langage...
    Bah c'est un peu ce que je reproche aux développeurs PHP en général (en faisant le troll) : soit disant c'est Open Source et GNU et libre et standard et je sais pas quoi d'autre, et donc forcément toute la merde qu'on peut faire avec c'est standard, beau, et tout ce qu'on veut.

    Sauf que de la merde pas standard, y'a que ça en PHP... bien plus que dans la plupart des autres langages qui disposent de librairies généralement réfléchies pour être interopérables...
    On ne jouit bien que de ce qu’on partage.

Discussions similaires

  1. Réponses: 3
    Dernier message: 03/01/2010, 20h53
  2. Réponses: 5
    Dernier message: 29/05/2008, 11h42
  3. Reproduire un fonctionnement "frames"
    Par vilcoy dans le forum VB.NET
    Réponses: 2
    Dernier message: 26/02/2007, 14h33
  4. [EasyPHP] [Apache] appel de fonction JS fonctionne dans .html et pas .php
    Par durand2504 dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 9
    Dernier message: 09/03/2006, 15h14
  5. appel de fonction JS fonctionne dans .html et pas .php
    Par durand2504 dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 01/03/2006, 15h10

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo