#!/usr/bin/perl use strict; use warnings; ###################################################################### # Quellen (-> Kurzbezeichnungen): # Manifest-Datei innerhalb meiner .ods-Datei als zip geöffnet META-INF\manifest.xml (-> "manifest") # https://docs.oasis-open.org/office/OpenDocument/v1.3/os/part2-packages/OpenDocument-v1.3-os-part2-packages.html (-> "oasis") # https://en.wikipedia.org/wiki/OpenDocument_technical_specification#Encryption (-> "wp") ###################################################################### # Crypt::CBC v.3.04 gem. Vorschlag von Linuxer an zwei Stellen angepasst, damit auch 16-Byte-Salts akzeptiert werden: # Zeile 402: croak "Argument to -salt must be a multiple of 8 bytes long" if defined $salt && (length $salt) % 8 && $salt ne '1'; # Zeile 633: (length $self->{salt}) % 8 and croak "Salt must be a multiple of 8 bytes long"; use Crypt::CBC; use MIME::Base64; # Die beiden folgenden sind alternativ (s.u.): use Crypt::Digest::SHA1 qw( sha1 ); use Crypt::Digest::SHA256 qw( sha256 ); use IO::Uncompress::Inflate qw(inflate $InflateError); # Nur zu Testzwecken (s. ganz unten): use IO::Compress::Deflate qw(deflate $DeflateError); use File::Slurp; my $xml_encr = read_file('content.xml') or die $!; # manifest:initialisation-vector="b6PjQ7EG+uWyhk/z29dJJQ==" my $iv = "b6PjQ7EG+uWyhk/z29dJJQ=="; # oasis Kap. 4.16.5: "The initialization vector is a base64Binary encoded sequence." $iv = decode_base64($iv); print "IV: $iv\n"; # manifest:salt="tHaDznWSd1OYCyWzFGx1YA==" my $salt = "tHaDznWSd1OYCyWzFGx1YA=="; # oasis Kap. 4.16.12 "The salt is encoded in the attribute value as a base64Binary value." $salt = decode_base64($salt); print "Salt: $salt\n"; # Mit diesem Passwort und LibreOffice Calc v.7.1.8.1 habe ich die Datei verschlüsselt: my $pwd = 'pwd123'; # oasis Kap. 3.4.2 Abs. 1: "The start key is generated: The byte sequence representing the password in UTF-8 is used # to generate a 20-byte SHA1 digest (see [RFC3174])." #$pwd = sha1($pwd); # wp: ODF versions 1.0 and 1.1 only mandate support for the SHA-1 digest here, while version 1.2 recommends SHA-256. # manifest:start-key-generation-name="http://www.w3.org/2000/09/xmldsig#sha256" $pwd = sha256($pwd); print "PWD: $pwd\n\n"; my $cipher = Crypt::CBC->new( -pass => $pwd , -iv => $iv , -salt => $salt # wp: "ODF 1.2 ... allows ... AES (with 128, 196 or 256 bits), ... in cipher block chaining mode" # manifest:algorithm-name="http://www.w3.org/2001/04/xmlenc#aes256-cbc" , -cipher => 'Cipher::AES' , -chain_mode => 'cbc' # manifest:key-size="32" , -keysize => 32 # manifest:key-derivation-name="PBKDF2" , -pbkdf => 'pbkdf2' # oasis Kap. 3.4.2 Abs. 2: "For each file, a 16-byte salt is generated by a random generator. The salt is used together # with the start key to derive a unique 128-bit key for each file. The default iteration count # for the algorithm is 1024." #, -iter => 1024 # manifest:iteration-count="100000" , -iter => 100000 , -header => 'none' # ISO10126Padding sollte lt. einer Quelle verwendet werden, das kann hier aber nicht eingestellt werden. , -padding => 'none' #, -hasher => ); my $xml_decr = $cipher->decrypt($xml_encr); print $xml_decr; print "\n\n----------------------------------------------------------------------\n\n"; # oasis Kap. 3.4.1 "Each file entry that is encrypted shall be compressed with the “deflate” algorithm before being encrypted." my $xml_decr_inflated; inflate \$xml_decr => \$xml_decr_inflated or die "inflate failed: $InflateError\n"; print $xml_decr_inflated; __END__ # Beispiel: print "\n\n----------------------------------------------------------------------\n\n"; #my $txt = read_file('manifest.xml'); # hier nur als Beispieltext my $txt = "Foo-nder-Bar"; my ($txt_deflated, $txt_inflated); deflate \$txt => \$txt_deflated or die "deflate failed: $InflateError\n"; print $txt_deflated; print "\n\n----------------------------------------------------------------------\n\n"; my $txt_deflated_encr = $cipher->encrypt($txt_deflated); print $txt_deflated_encr; print "\n\n----------------------------------------------------------------------\n\n"; my $txt_deflated_decr = $cipher->decrypt($txt_deflated_encr); print $txt_deflated_decr; print "\n\n----------------------------------------------------------------------\n\n"; inflate \$txt_deflated_decr => \$txt_inflated or die "inflate failed: $InflateError\n"; print $txt_inflated