sub
DEFAULT_CMDV {
return
[];
}
sub
DEFAULT_CMDSTORE {
return
[];
}
sub
DEFAULT_CMD {
return
[];
}
sub
_detect_cmd {
my
(
$cmd
,
$default
) =
@_
;
if
(!
defined
$cmd
||
$cmd
eq
'auto'
) {
return
first { find_command(
$_
) } @{
$default
};
}
elsif
(
$cmd
eq
'none'
) {
return
;
}
else
{
return
find_command(
$cmd
);
}
}
sub
new {
my
(
$this
,
%opts
) =
@_
;
my
$class
=
ref
(
$this
) ||
$this
;
my
$self
= {};
bless
$self
,
$class
;
$self
->{cmdv} = _detect_cmd(
$opts
{cmdv},
$self
->DEFAULT_CMDV());
$self
->{cmdstore} = _detect_cmd(
$opts
{cmdstore},
$self
->DEFAULT_CMDSTORE());
$self
->{cmd} = _detect_cmd(
$opts
{cmd},
$self
->DEFAULT_CMD());
return
$self
;
}
sub
has_backend_cmd {
my
$self
=
shift
;
return
defined
$self
->{cmd};
}
sub
has_verify_cmd {
my
$self
=
shift
;
return
1
if
@{
$self
->DEFAULT_CMDV()} &&
defined
$self
->{cmdv};
return
1
if
defined
$self
->{cmd};
return
0;
}
sub
has_keystore {
my
$self
=
shift
;
return
0;
}
sub
can_use_key {
my
(
$self
,
$key
) =
@_
;
return
$self
->has_keystore()
if
$key
->needs_keystore();
return
1;
}
sub
get_trusted_keyrings {
my
$self
=
shift
;
return
();
}
sub
_pgp_dearmor_data {
my
(
$type
,
$data
,
$filename
) =
@_
;
my
$armor_regex
=
qr{
-----BEGIN\ PGP\ \Q$type\E-----[\r\t ]*\n
(?:[^:\n]+:\ [^\n]*[\r\t ]*\n)*
[\r\t ]*\n
([a-zA-Z0-9/+\n]+={0,2}
)[\r\t ]*\n
(?:=[a-zA-Z0-9/+]{4}[\r\t ]*\n)?
-----END\ PGP\ \Q
$type
\E-----
}xm;
my
$blocks
= 0;
my
$binary
;
while
(
$data
=~ m/
$armor_regex
/g) {
$binary
.= decode_base64($1);
$blocks
++;
}
if
(
$blocks
> 1) {
warning(g_(
'multiple concatenated ASCII Armor blocks in %s, '
.
'which is not an interoperable construct, see <%s>'
),
$filename
,
hint(g_(
'sq keyring merge --overwrite --output %s %s'
),
$filename
,
$filename
);
}
return
$binary
;
}
sub
_pgp_armor_checksum {
my
(
$data
) =
@_
;
my
$CRC24_INIT
= 0xB704CE;
my
$CRC24_GENERATOR
= 0x864CFB;
my
@bytes
=
unpack
'C*'
,
$data
;
my
$crc
=
$CRC24_INIT
;
for
my
$b
(
@bytes
) {
$crc
^= (
$b
<< 16);
for
(1 .. 8) {
$crc
<<= 1;
if
(
$crc
& 0x1000000) {
$crc
&= 0xffffff;
$crc
^=
$CRC24_GENERATOR
;
}
}
}
my
$sum
=
pack
'CCC'
, (
$crc
>> 16) & 0xff, (
$crc
>> 8) & 0xff,
$crc
& 0xff;
return
encode_base64(
$sum
,
q{}
);
}
sub
_pgp_armor_data {
my
(
$type
,
$data
) =
@_
;
my
$out
= encode_base64(
$data
,
q{}
) =~ s/(.{1,64})/$1\n/gr;
chomp
$out
;
my
$crc
= _pgp_armor_checksum(
$data
);
my
$armor
= <<~
"ARMOR"
;
-----BEGIN PGP
$type
-----
$out
=
$crc
-----END PGP
$type
-----
ARMOR
return
$armor
;
}
sub
armor {
my
(
$self
,
$type
,
$in
,
$out
) =
@_
;
my
$raw_data
= file_slurp(
$in
);
my
$data
= _pgp_dearmor_data(
$type
,
$raw_data
,
$in
) //
$raw_data
;
my
$armor
= _pgp_armor_data(
$type
,
$data
);
return
OPENPGP_BAD_DATA
unless
defined
$armor
;
file_dump(
$out
,
$armor
);
return
OPENPGP_OK;
}
sub
dearmor {
my
(
$self
,
$type
,
$in
,
$out
) =
@_
;
my
$armor
= file_slurp(
$in
);
my
$data
= _pgp_dearmor_data(
$type
,
$armor
,
$in
);
return
OPENPGP_BAD_DATA
unless
defined
$data
;
file_dump(
$out
,
$data
);
return
OPENPGP_OK;
}
sub
inline_verify {
my
(
$self
,
$inlinesigned
,
$data
,
@certs
) =
@_
;
return
OPENPGP_UNSUPPORTED_SUBCMD;
}
sub
verify {
my
(
$self
,
$data
,
$sig
,
@certs
) =
@_
;
return
OPENPGP_UNSUPPORTED_SUBCMD;
}
sub
inline_sign {
my
(
$self
,
$data
,
$inlinesigned
,
$key
) =
@_
;
return
OPENPGP_UNSUPPORTED_SUBCMD;
}
1;