diff --git a/nur_src/passwd/AbstractGenerator.php b/nur_src/passwd/AbstractGenerator.php new file mode 100644 index 0000000..5bdfc0d --- /dev/null +++ b/nur_src/passwd/AbstractGenerator.php @@ -0,0 +1,68 @@ + "xese", + "sexy" => "xyse", + "suce" => "cesu", + "bite" => "tebi", + "cabo" => "boca", + "pipe" => "pepi", + "cocu" => "cuco", + "pute" => "tepu", + ]; + + function __construct(?int $nbBlocks=null, ?int $nbPuncts=null) { + if ($nbBlocks === null) $nbBlocks = static::NB_BLOCKS; + if ($nbPuncts === null) $nbPuncts = static::NB_PUNCTS; + if ($nbBlocks < 1) $nbBlocks = 1; + if ($nbPuncts > $nbBlocks) $nbPuncts = $nbBlocks; + $this->nbBlocks = $nbBlocks; + $this->nbPuncts = $nbPuncts; + } + + /** @var int */ + protected $nbBlocks, $nbPuncts; + + function generate(?int $nbBlocks=null, ?int $nbPuncts=null, ?int $seed=null): string { + if ($nbBlocks === null) $nbBlocks = $this->nbBlocks; + if ($nbPuncts === null) $nbPuncts = $this->nbPuncts; + if ($seed !== null) mt_srand($seed); + $maxc = strlen(self::CONSONNES) - 1; + $maxv = strlen(self::VOYELLES) - 1; + $maxp = strlen(self::PUNCTS) - 1; + $size = $nbBlocks * 2; + $sindex = 0; + $syllabes = []; + while ($sindex < $size) { + $lindex = count($syllabes) - 1; + do { + $consonne = self::CONSONNES[mt_rand(0, $maxc)]; + $voyelle = self::VOYELLES[mt_rand(0, $maxv)]; + $syllabe = $consonne.$voyelle; + # pas deux fois la même syllabe de suite + $repetition = ($lindex >= 0 && $syllabes[$lindex] == $syllabe) + || ($lindex >= 1 && $syllabes[$lindex - 1] == $syllabe); + } while ($repetition); + $syllabes[] = $syllabe; + $sindex++; + if ($nbPuncts > 0 && $sindex % 2 == 0 && mt_rand() % 2 == 0) { + $syllabes[] = self::PUNCTS[mt_rand(0, $maxp)]; + $nbPuncts--; + } + } + $password = implode("", $syllabes); + foreach (self::MAPPINGS as $from => $to) { + $password = str_replace($from, $to, $password); + } + return $password; + } +} diff --git a/nur_src/passwd/EtuPasswordGenerator.php b/nur_src/passwd/EtuPasswordGenerator.php new file mode 100644 index 0000000..7e05c5b --- /dev/null +++ b/nur_src/passwd/EtuPasswordGenerator.php @@ -0,0 +1,76 @@ +version = $version; + } + + private $version; + + function getVersion(): int { + return $this->version; + } + + function generate(int $codEtu, ?int $version=null): string { + if ($version === null) $version = $this->version; + switch ($version) { + case self::V2: return $this->generate2($codEtu); + case self::V3: return $this->generate3($codEtu); + case self::V4: return $this->generate4($codEtu); + default: throw ValueException::invalid_value($version, "version"); + } + } + + private static $generate2_groups; + static function init_generate2(array $groups): void { + self::$generate2_groups = $groups; + } + + protected function generate2(int $codEtu): string { + $groups = self::$generate2_groups; + if ($groups == null) { + throw IllegalAccessException::unexpected_state("init_generate2"); + } + $pass = ""; + for ($i = 0; $i < 8; $i++) { + $group = $groups[$i]; + $grouplen = strlen($group); + $pass .= $group[$codEtu % $grouplen]; + } + return $pass; + } + + /** @var PasswordGenerator */ + private $pg; + + /** @var callable */ + private static $gen3seed; + + static function init_gen3seed(callable $seed): void { + self::$gen3seed = $seed; + } + + protected function generate3(int $codEtu): string { + if ($this->pg === null) $this->pg = new PasswordGenerator(); + return $this->pg->generate(3, 1, (self::$gen3seed)($codEtu)); + } + + /** @var callable */ + private static $gen4seed; + + static function init_gen4seed(callable $seed): void { + self::$gen4seed = $seed; + } + + protected function generate4(int $codEtu): string { + if ($this->pg === null) $this->pg = new PasswordGenerator(); + return $this->pg->generate(4, 1, (self::$gen4seed)($codEtu)); + } +} diff --git a/nur_src/passwd/PasswordGenerator.php b/nur_src/passwd/PasswordGenerator.php new file mode 100644 index 0000000..fa1a9d5 --- /dev/null +++ b/nur_src/passwd/PasswordGenerator.php @@ -0,0 +1,10 @@ +> 1); + $key[] = ($tmp[1] << 6) | ($tmp[2] >> 2); + $key[] = ($tmp[2] << 5) | ($tmp[3] >> 3); + $key[] = ($tmp[3] << 4) | ($tmp[4] >> 4); + $key[] = ($tmp[4] << 3) | ($tmp[5] >> 5); + $key[] = ($tmp[5] << 2) | ($tmp[6] >> 6); + $key[] = $tmp[6] << 1; + + $key0 = ""; + foreach ($key as $k) { + $key0 .= chr($k); + } + $crypt = openssl_encrypt("KGS!@#$%", "des-ecb", $key0 + , OPENSSL_RAW_DATA + OPENSSL_ZERO_PADDING); + + return bin2hex($crypt); + } + + static function lm(string $clear): string { + $string = strtoupper(substr($clear,0,14)); + $part1 = self::lm_des_encrypt(substr($string, 0, 7)); + $part2 = self::lm_des_encrypt(substr($string, 7, 7)); + return strtoupper($part1.$part2); + } + + private static $lsc_key; + + static function init_lsc(string $key): void { + self::$lsc_key = hex2bin($key); + } + private static function lsc_key(): string { + $lsc_key = self::$lsc_key; + if ($lsc_key === null) { + throw IllegalAccessException::unexpected_state("init_lsc"); + } + return $lsc_key; + } + + static function is_lsc_available(): bool { + return self::$lsc_key !== null; + } + + static function decrypt_lsc(string $lsc): string { + return openssl_decrypt($lsc, "aes-128-ecb", self::lsc_key()); + } + + static function encrypt_lsc(string $clear): string { + return openssl_encrypt($clear, "aes-128-ecb", self::lsc_key()); + } +} diff --git a/nur_tbin/dump-passwords.php b/nur_tbin/dump-passwords.php new file mode 100755 index 0000000..7ada629 --- /dev/null +++ b/nur_tbin/dump-passwords.php @@ -0,0 +1,51 @@ +#!/usr/bin/php + "version", "value" => 2], + ["-3", "name" => "version", "value" => 3], + ["-4", "name" => "version", "value" => 4], + ]; + + protected $version; + + protected $args; + + function main() { + $version = $this->version; + if ($version === null) $version = 4; + $pg = new class($version) extends EtuPasswordGenerator { + function gen3seed(int $codEtu): int { + return parent::gen3seed($codEtu); + } + function gen4seed(int $codEtu): int { + return parent::gen4seed($codEtu); + } + }; + $year = intval(date("y")); + $prefix = intval(A::get($this->args, 0, $year + 20)) % 100; + + $codetu = $prefix * 1000000 + 1; + $max = ($prefix + 1) * 1000000; + $prev = 0; + echo "codetu,seed,delta,password\n"; + while ($codetu < $max) { + switch ($version) { + case 3: $seed = $pg->gen3seed($codetu); break; + case 4: $seed = $pg->gen4seed($codetu); break; + default: $seed = null; break; + } + $delta = $seed - $prev; + $password = $pg->generate($codetu); + echo "$codetu,$seed,$delta,\"$password\"\n"; + $prev = $seed; + $codetu++; + } + } +}); diff --git a/nur_tests/passwd/PasswordGeneratorTest.php b/nur_tests/passwd/PasswordGeneratorTest.php new file mode 100644 index 0000000..21df4b4 --- /dev/null +++ b/nur_tests/passwd/PasswordGeneratorTest.php @@ -0,0 +1,12 @@ +generate(null, null, 0)); + self::assertSame("gurazefe", $pg->generate(2, null, 0)); + } +} diff --git a/nur_tests/passwd/passwordsTest.php b/nur_tests/passwd/passwordsTest.php new file mode 100644 index 0000000..74d6a76 --- /dev/null +++ b/nur_tests/passwd/passwordsTest.php @@ -0,0 +1,16 @@ +