ajout nur/passwd
This commit is contained in:
parent
86ce10cf95
commit
5ca55e1919
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
namespace nur\passwd;
|
||||
|
||||
abstract class AbstractGenerator {
|
||||
const NB_BLOCKS = 4;
|
||||
const NB_PUNCTS = 2;
|
||||
|
||||
const CONSONNES = "bcdfghjklmnpqrstvwxz";
|
||||
const VOYELLES = "aeiuoy";
|
||||
const PUNCTS = "+-*/=!@?:#";
|
||||
const MAPPINGS = [
|
||||
# éviter certaines combinaisons potentiellement gênantes
|
||||
"sexe" => "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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
namespace nur\passwd;
|
||||
|
||||
use nur\b\IllegalAccessException;
|
||||
use nur\b\ValueException;
|
||||
|
||||
class EtuPasswordGenerator {
|
||||
const V2 = 2, V3 = 3, V4 = 4;
|
||||
|
||||
function __construct(?int $version=null) {
|
||||
if ($version === null) $version = self::V4;
|
||||
$this->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));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
namespace nur\passwd;
|
||||
|
||||
class PasswordGenerator extends AbstractGenerator {
|
||||
function generate(?int $nbBlocks=null, ?int $nbPuncts=null, ?int $seed=null): string {
|
||||
# toujours réinitialiser le seed
|
||||
if ($seed === null) mt_srand();
|
||||
return parent::generate($nbBlocks, $nbPuncts, $seed);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
namespace nur\passwd;
|
||||
|
||||
use nur\b\IllegalAccessException;
|
||||
|
||||
/**
|
||||
* Class passwords; outils pour gérer les mots de passe
|
||||
*/
|
||||
class passwords {
|
||||
/** obtenir le salt d'un mot de passe hashé en CRYPT */
|
||||
static function get_des_crypt_salt(string $crypt): string {
|
||||
return substr($crypt, 0, 2);
|
||||
}
|
||||
|
||||
static function des_crypt(string $clear, ?string $salt=null): string {
|
||||
if ($salt === null) $salt = "AA";
|
||||
return crypt($clear, $salt);
|
||||
}
|
||||
|
||||
static function sha(string $clear): string {
|
||||
return base64_encode(sha1($clear, true));
|
||||
}
|
||||
|
||||
static function xsha(string $clear): string {
|
||||
return strtoupper(sha1($clear));
|
||||
}
|
||||
|
||||
/** obtenir le salt d'un mot de passe hashé en SSHA */
|
||||
static function get_ssha_salt(string $ssha): string {
|
||||
return substr(base64_decode($ssha), 20);
|
||||
}
|
||||
|
||||
static function ssha(string $clear, ?string $salt=null): string {
|
||||
if ($salt === null) $salt = random_bytes(20);
|
||||
return base64_encode(sha1("$clear$salt", true).$salt);
|
||||
}
|
||||
|
||||
static function ntlm(string $clear): string {
|
||||
$string = iconv("UTF-8", "UTF-16LE", $clear);
|
||||
return strtoupper(bin2hex(hash("md4", $string, true)));
|
||||
}
|
||||
|
||||
private static function lm_des_encrypt(string $string) {
|
||||
$len = strlen($string);
|
||||
$tmp = [];
|
||||
for ($i = 0; $i < 7; $i++) {
|
||||
$tmp[] = $i < $len? ord($string[$i]): 0;
|
||||
}
|
||||
$key = [];
|
||||
$key[] = $tmp[0] & 254;
|
||||
$key[] = ($tmp[0] << 7) | ($tmp[1] >> 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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/php
|
||||
<?php
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
use nur\A;
|
||||
use nur\cli\Application;
|
||||
use nur\passwd\EtuPasswordGenerator;
|
||||
|
||||
Application::run(new class extends Application {
|
||||
const ARGS = [
|
||||
["-2", "name" => "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++;
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
namespace nur\passwd;
|
||||
|
||||
use nur\t\TestCase;
|
||||
|
||||
class PasswordGeneratorTest extends TestCase {
|
||||
function testGenerate(): void {
|
||||
$pg = new PasswordGenerator();
|
||||
self::assertSame("gurazefecivuvali@", $pg->generate(null, null, 0));
|
||||
self::assertSame("gurazefe", $pg->generate(2, null, 0));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
namespace nur\passwd;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class passwordsTest extends TestCase {
|
||||
function testNtlmPasswords(): void {
|
||||
$password = "tagada";
|
||||
self::assertSame("A725F22CD78658E45CF6E08670BFBA70", passwords::ntlm($password));
|
||||
self::assertSame("93F202BB581683A7AAD3B435B51404EE", passwords::lm($password));
|
||||
|
||||
$password = "tagadatsointsoinpouetpouet";
|
||||
self::assertSame("F25F2A1C672FEE777A480411AC0D68F6", passwords::ntlm($password));
|
||||
self::assertSame("06E39E786C60859072548ACC457CF244", passwords::lm($password));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||
mydir="$(dirname -- "$0")"
|
||||
"$mydir/vendor/bin/phpunit" --bootstrap "$mydir/vendor/autoload.php" "$@" "$mydir/nur_tests"
|
|
@ -46,3 +46,10 @@ FROM=../nur-mapper
|
|||
sy src/ nur_src/mapper/
|
||||
sy tests/ nur_tests/mapper/
|
||||
sy tbin/ nur_tbin/
|
||||
|
||||
FROM=../nur-passwd
|
||||
sy src/ nur_src/passwd/
|
||||
sy tests/ nur_tests/passwd/
|
||||
sy tbin/ nur_tbin/
|
||||
|
||||
./nur_sbin/update_classes.php
|
||||
|
|
Loading…
Reference in New Issue