fpspreadsheet: Fix Excel password hash calculation (patch by shobits1).

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5792 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2017-03-05 23:16:43 +00:00
parent 16118290c5
commit 06688f42e1
3 changed files with 57 additions and 30 deletions

View File

@ -5,28 +5,42 @@ interface
uses
SysUtils, fpsTypes;
function AlgorithmToStr(Algorithm: TsCryptoAlgorithm): String;
type
TsAlgorithmUsage = (auExcel, auOpenDocument);
function AlgorithmToStr(Algorithm: TsCryptoAlgorithm; AUsage: TsAlgorithmUsage): String;
function StrToAlgorithm(const AName: String): TsCryptoAlgorithm;
function ExcelPasswordHash(const APassword: String): String;
implementation
function AlgorithmToStr(Algorithm: TsCryptoAlgorithm): String;
uses
LazUTF8;
function AlgorithmToStr(Algorithm: TsCryptoAlgorithm; AUsage: TsAlgorithmUsage): String;
begin
case Algorithm of
caExcel : Result := 'EXCEL';
caMD2 : Result := 'MD2';
caMD4 : Result := 'MD4';
caMD5 : Result := 'MD5';
caRIPEMD128 : Result := 'RIPEMD-128';
caRIPEMD160 : Result := 'RIPEMD-160';
caSHA1 : Result := 'SHA-1';
caSHA256 : Result := 'SHA-256';
caSHA384 : Result := 'SHA-384';
caSHA512 : Result := 'SHA-512';
caWHIRLPOOL : Result := 'WHIRLPOOL';
else Result := '';
Result := '';
case AUsage of
auExcel:
case Algorithm of
caExcel : Result := 'EXCEL';
caMD2 : Result := 'MD2';
caMD4 : Result := 'MD4';
caMD5 : Result := 'MD5';
caRIPEMD128 : Result := 'RIPEMD-128';
caRIPEMD160 : Result := 'RIPEMD-160';
caSHA1 : Result := 'SHA-1';
caSHA256 : Result := 'SHA-256';
caSHA384 : Result := 'SHA-384';
caSHA512 : Result := 'SHA-512';
caWHIRLPOOL : Result := 'WHIRLPOOL';
end;
auOpenDocument:
case Algorithm of
caSHA1 : Result := 'http://www.w3.org/2000/09/xmldsig#sha1';
caSHA256 : Result := 'http://www.w3.org/2000/09/xmldsig#sha256';
end;
end;
end;
@ -56,22 +70,35 @@ begin
end;
end;
{@@ This is the code for generating Excel 2010 and earlier password's hash }
function ExcelPasswordHash(const APassword: string): string;
const
Key = $CE4B;
{@@ This is the code for generating Excel 2010 and earlier password's hash
See: http://forum.lazarus.freepascal.org/index.php/topic,36075.msg240132.html#msg240132 }
function ExcelPasswordHash( const APassword: string ): string;
var
i: Integer;
HashValue: Word = 0;
PassLen: Integer;
Password: string;
PassHash: Word = 0;
begin
for i:= Length(APassword) downto 1 do
// we are needed to work with single byte character.
Password:= UTF8ToWinCP(APassword);
PassLen := Length(Password);
if PassLen = 0 then
begin
HashValue := ord(APassword[i]) xor HashValue;
HashValue := HashValue shl 1;
Result := '';
exit;
end;
HashValue := HashValue xor Length(APassword) xor Key;
Result := IntToHex(HashValue, 4);
for i:= PassLen downto 1 do
begin
PassHash:= ((PassHash shr 14) and $0001) or ((PassHash shl 1) and $7fff);
PassHash:= PassHash xor ord(Password[i]);
end;
PassHash:= ((PassHash shr 14) and $0001) or ((PassHash shl 1) and $7fff);
PassHash:= PassHash xor PassLen xor $CE4B;
Result := IntToHex(PassHash, 4);
end;
end.

View File

@ -3435,7 +3435,7 @@ begin
s := s + ' hashValue="' + AWorksheet.CryptoInfo.PasswordHash + '"';
if AWorksheet.CryptoInfo.Algorithm <> caUnknown then
s := s + ' algorithmName="' + AlgorithmToStr(AWorksheet.CryptoInfo.Algorithm) + '"';
s := s + ' algorithmName="' + AlgorithmToStr(AWorksheet.CryptoInfo.Algorithm, auExcel) + '"';
if AWorksheet.CryptoInfo.SaltValue <> '' then
s := s + ' saltValue="' + AWorksheet.CryptoInfo.SaltValue + '"';
@ -4676,7 +4676,7 @@ begin
begin
s:= s + ' workbookHashVal="' + Workbook.CryptoInfo.PasswordHash + '"';
if Workbook.CryptoInfo.Algorithm <> caUnknown then
s:= s + ' workbookAlgorithmName="' + AlgorithmToStr(Workbook.CryptoInfo.Algorithm) + '"';
s:= s + ' workbookAlgorithmName="' + AlgorithmToStr(Workbook.CryptoInfo.Algorithm, auExcel) + '"';
if Workbook.CryptoInfo.SaltValue <> '' then
s:= s + ' workbookSaltValue="' + Workbook.CryptoInfo.SaltValue + '"';

View File

@ -3654,7 +3654,7 @@ begin
if (ienCryptoInfo in FExpanded) then begin
AStrings.Add('(-) CryptoInfo=');
AStrings.Add(Format(' PasswordHash=%s', [Workbook.CryptoInfo.PasswordHash]));
AStrings.Add(Format(' Algorithm=%s', [AlgorithmToStr(Workbook.CryptoInfo.Algorithm)]));
AStrings.Add(Format(' Algorithm=%s', [AlgorithmToStr(Workbook.CryptoInfo.Algorithm, auExcel)]));
AStrings.Add(Format(' SaltValue=%s', [Workbook.CryptoInfo.SaltValue]));
AStrings.Add(Format(' SpinCount=%d', [Workbook.CryptoInfo.SpinCount]));
end else
@ -3837,7 +3837,7 @@ begin
if (ienCryptoInfo in FExpanded) then begin
AStrings.Add('(-) CryptoInfo=');
AStrings.Add(Format(' PasswordHash=%s', [Worksheet.CryptoInfo.PasswordHash]));
AStrings.Add(Format(' Algorithm=%s', [AlgorithmToStr(Worksheet.CryptoInfo.Algorithm)]));
AStrings.Add(Format(' Algorithm=%s', [AlgorithmToStr(Worksheet.CryptoInfo.Algorithm, auExcel)]));
AStrings.Add(Format(' SaltValue=%s', [Worksheet.CryptoInfo.SaltValue]));
AStrings.Add(Format(' SpinCount=%d', [Worksheet.CryptoInfo.SpinCount]));
end else