mirror of
https://github.com/webmin/webmin.git
synced 2026-05-06 23:30:29 +01:00
Some checks failed
webmin.dev: webmin/webmin / build (push) Has been cancelled
Webmin now uses the bundled QRCode::Encoder implementation by default to generate TOTP QR codes locally and inline, without relying on qr.cgi or external services. This encoder requires Perl 5.24 or newer, so qrencode is no longer included as a recommended package dependency. On older systems where the bundled encoder cannot run, admins can still install qrencode manually to restore QR generation support. Systems old enough to lack Perl 5.24 are typically already well past their supported security lifecycle, so keeping qrencode preinstalled by default is no longer treated as a packaging requirement. When neither option is available, Webmin falls back cleanly to manual TOTP setup using the shared secret. https://github.com/webmin/webmin/issues/2667#issuecomment-4247431279 [no-build]
118 lines
2.8 KiB
Perl
118 lines
2.8 KiB
Perl
# Liberally adapted from:
|
|
# https://en.wikiversity.org/wiki/Reed%E2%80%93Solomon_codes_for_coders
|
|
|
|
package Math::ReedSolomon::Encoder;
|
|
use v5.24;
|
|
use warnings;
|
|
use experimental qw< signatures >;
|
|
{ our $VERSION = '0.001' }
|
|
|
|
use Exporter qw< import >;
|
|
our @EXPORT_OK = qw<
|
|
rs_correction
|
|
rs_correction_string
|
|
rs_encode
|
|
rs_encode_string
|
|
>;
|
|
our %EXPORT_TAGS = (all => [ @EXPORT_OK ]);
|
|
|
|
our $ALPHA = 2;
|
|
our $PRIME_POLY = 0X11D;
|
|
|
|
########################################################################
|
|
#
|
|
# Public Interface
|
|
|
|
sub rs_correction ($msg, $nsym) {
|
|
my $g = _rs_generator_poly($nsym);
|
|
my ($quot, $rem) = _gf256_poly_div([$msg->@*, (0) x $nsym ], $g);
|
|
return $rem;
|
|
}
|
|
|
|
sub rs_correction_string ($msg, $nsym) {
|
|
my $aref = [ map { ord($_) } split m{}mxs, $msg ];
|
|
return join '', map { chr($_) } rs_correction($aref, $nsym)->@*;
|
|
}
|
|
|
|
sub rs_encode ($msg, $nsym) {
|
|
return [ $msg->@*, rs_correction($msg, $nsym)->@* ];
|
|
}
|
|
|
|
sub rs_encode_string ($msg, $nsym) {
|
|
return $msg . rs_correction_string($msg, $nsym);
|
|
}
|
|
|
|
|
|
########################################################################
|
|
#
|
|
# Private Interface
|
|
|
|
sub _rs_generator_poly ($nsym) {
|
|
state $gs = [ [1] ];
|
|
push $gs->@*, _gf256_poly_mul($gs->[-1], [1, _gf256_pow($ALPHA, $gs->$#*)])
|
|
while $nsym > $gs->$#*;
|
|
return $gs->[$nsym];
|
|
}
|
|
|
|
sub _gf256_table_for {
|
|
state $table_for = do {
|
|
my (@exp, @log);
|
|
my $x = 1;
|
|
for my $i (0 .. 254) {
|
|
$exp[$i] = $exp[$i + 255] = $x;
|
|
$log[$x] = $i;
|
|
$x <<= 1;
|
|
$x ^= $PRIME_POLY if $x & 0x100;
|
|
}
|
|
{ exp => \@exp, log => \@log };
|
|
};
|
|
}
|
|
|
|
sub _gf256_mul ($x, $y) {
|
|
state $table_for = _gf256_table_for();
|
|
state $exp = $table_for->{exp};
|
|
state $log = $table_for->{log};
|
|
return 0 if $x == 0 || $y == 0;
|
|
return $exp->[$log->[$x] + $log->[$y]];
|
|
}
|
|
|
|
sub _gf256_pow ($x, $pow) {
|
|
state $table_for = _gf256_table_for();
|
|
state $exp = $table_for->{exp};
|
|
state $log = $table_for->{log};
|
|
return $exp->[($log->[$x] * $pow) % 255];
|
|
}
|
|
|
|
sub _gf256_poly_mul ($p, $q) {
|
|
my $lp = $p->@*;
|
|
my $lq = $q->@*;
|
|
my $lr = $lp + $lq - 1;
|
|
my $r = [ (0) x $lr ];
|
|
for my $i (0 .. ($lp - 1)) {
|
|
for my $j (0 .. ($lq - 1)) {
|
|
$r->[$i + $j] ^= _gf256_mul($p->[$i], $q->[$j]);
|
|
}
|
|
}
|
|
return $r;
|
|
}
|
|
|
|
sub _gf256_poly_div ($x, $y) {
|
|
my $retval = [ $x->@* ];
|
|
for my $i (0 .. ($x->$#* - $y->$#*)) {
|
|
my $c = $retval->[$i];
|
|
if ($c != 0) {
|
|
for my $j (1 .. $y->$#*) {
|
|
if ($y->[$j] != 0) {
|
|
$retval->[$i + $j] ^= _gf256_mul($y->[$j], $c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
my $separator = $retval->$#* - $y->$#*;
|
|
my $quot = [ $retval->@[0 .. $separator] ];
|
|
my $rem = [ $retval->@[$separator + 1 .. $retval->$#*] ];
|
|
return ($quot, $rem);
|
|
}
|
|
|
|
1;
|