1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svl.hxx"
26
27 #include <svl/PasswordHelper.hxx>
28 #include <rtl/digest.h>
29 #include <tools/string.hxx>
30
31 using namespace com::sun::star;
32
33 namespace
34 {
35 const sal_uInt32 SHA256_K[64] = {
36 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
37 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
38 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
39 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
40 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
41 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
42 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
43 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
44 };
45
lcl_Rotr(sal_uInt32 n,int b)46 inline sal_uInt32 lcl_Rotr( sal_uInt32 n, int b ) { return ( n >> b ) | ( n << ( 32 - b ) ); }
47
lcl_Sha256Block(sal_uInt32 * pState,const sal_uInt8 * pBlock)48 void lcl_Sha256Block( sal_uInt32* pState, const sal_uInt8* pBlock )
49 {
50 sal_uInt32 w[64];
51 for( int i = 0; i < 16; ++i )
52 w[i] = ( sal_uInt32( pBlock[4*i] ) << 24 ) | ( sal_uInt32( pBlock[4*i+1] ) << 16 ) |
53 ( sal_uInt32( pBlock[4*i+2] ) << 8 ) | sal_uInt32( pBlock[4*i+3] );
54 for( int i = 16; i < 64; ++i )
55 {
56 const sal_uInt32 s0 = lcl_Rotr( w[i-15], 7 ) ^ lcl_Rotr( w[i-15], 18 ) ^ ( w[i-15] >> 3 );
57 const sal_uInt32 s1 = lcl_Rotr( w[i-2], 17 ) ^ lcl_Rotr( w[i-2], 19 ) ^ ( w[i-2] >> 10 );
58 w[i] = w[i-16] + s0 + w[i-7] + s1;
59 }
60 sal_uInt32 a = pState[0], b = pState[1], c = pState[2], d = pState[3];
61 sal_uInt32 e = pState[4], f = pState[5], g = pState[6], h = pState[7];
62 for( int i = 0; i < 64; ++i )
63 {
64 const sal_uInt32 t1 = h + ( lcl_Rotr( e, 6 ) ^ lcl_Rotr( e, 11 ) ^ lcl_Rotr( e, 25 ) ) +
65 ( ( e & f ) ^ ( ~e & g ) ) + SHA256_K[i] + w[i];
66 const sal_uInt32 t2 = ( lcl_Rotr( a, 2 ) ^ lcl_Rotr( a, 13 ) ^ lcl_Rotr( a, 22 ) ) +
67 ( ( a & b ) ^ ( a & c ) ^ ( b & c ) );
68 h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;
69 }
70 pState[0] += a; pState[1] += b; pState[2] += c; pState[3] += d;
71 pState[4] += e; pState[5] += f; pState[6] += g; pState[7] += h;
72 }
73
74 // sal has no SHA-256; FIPS 180-4
lcl_Sha256(const sal_uInt8 * pData,sal_uInt32 nLen,sal_uInt8 * pOut)75 void lcl_Sha256( const sal_uInt8* pData, sal_uInt32 nLen, sal_uInt8* pOut )
76 {
77 sal_uInt32 aState[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
78 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
79 sal_uInt32 nDone = 0;
80 for( ; nLen - nDone >= 64; nDone += 64 )
81 lcl_Sha256Block( aState, pData + nDone );
82
83 sal_uInt8 aTail[128] = { 0 };
84 const sal_uInt32 nRest = nLen - nDone;
85 for( sal_uInt32 i = 0; i < nRest; ++i )
86 aTail[i] = pData[nDone + i];
87 aTail[nRest] = 0x80;
88 const sal_uInt32 nTailLen = nRest < 56 ? 64 : 128;
89 const sal_uInt64 nBits = sal_uInt64( nLen ) * 8;
90 for( int i = 0; i < 8; ++i )
91 aTail[nTailLen - 1 - i] = sal_uInt8( nBits >> ( 8 * i ) );
92 for( sal_uInt32 i = 0; i < nTailLen; i += 64 )
93 lcl_Sha256Block( aState, aTail + i );
94
95 for( int i = 0; i < 8; ++i )
96 for( int j = 0; j < 4; ++j )
97 pOut[4*i+j] = sal_uInt8( aState[i] >> ( 24 - 8 * j ) );
98 }
99 }
100
GetHashPassword(uno::Sequence<sal_Int8> & rPassHash,const sal_Char * pPass,sal_uInt32 nLen)101 void SvPasswordHelper::GetHashPassword(uno::Sequence<sal_Int8>& rPassHash, const sal_Char* pPass, sal_uInt32 nLen)
102 {
103 rPassHash.realloc(RTL_DIGEST_LENGTH_SHA1);
104
105 rtlDigestError aError = rtl_digest_SHA1 (pPass, nLen, reinterpret_cast<sal_uInt8*>(rPassHash.getArray()), rPassHash.getLength());
106 if (aError != rtl_Digest_E_None)
107 {
108 rPassHash.realloc(0);
109 }
110 }
111
GetHashPasswordLittleEndian(uno::Sequence<sal_Int8> & rPassHash,const String & sPass)112 void SvPasswordHelper::GetHashPasswordLittleEndian(uno::Sequence<sal_Int8>& rPassHash, const String& sPass)
113 {
114 xub_StrLen nSize(sPass.Len());
115 sal_Char* pCharBuffer = new sal_Char[nSize * sizeof(sal_Unicode)];
116
117 for (xub_StrLen i = 0; i < nSize; ++i)
118 {
119 sal_Unicode ch(sPass.GetChar(i));
120 pCharBuffer[2 * i] = static_cast< sal_Char >(ch & 0xFF);
121 pCharBuffer[2 * i + 1] = static_cast< sal_Char >(ch >> 8);
122 }
123
124 GetHashPassword(rPassHash, pCharBuffer, nSize * sizeof(sal_Unicode));
125
126 delete[] pCharBuffer;
127 }
128
GetHashPasswordBigEndian(uno::Sequence<sal_Int8> & rPassHash,const String & sPass)129 void SvPasswordHelper::GetHashPasswordBigEndian(uno::Sequence<sal_Int8>& rPassHash, const String& sPass)
130 {
131 xub_StrLen nSize(sPass.Len());
132 sal_Char* pCharBuffer = new sal_Char[nSize * sizeof(sal_Unicode)];
133
134 for (xub_StrLen i = 0; i < nSize; ++i)
135 {
136 sal_Unicode ch(sPass.GetChar(i));
137 pCharBuffer[2 * i] = static_cast< sal_Char >(ch >> 8);
138 pCharBuffer[2 * i + 1] = static_cast< sal_Char >(ch & 0xFF);
139 }
140
141 GetHashPassword(rPassHash, pCharBuffer, nSize * sizeof(sal_Unicode));
142
143 delete[] pCharBuffer;
144 }
145
GetHashPasswordUTF8(uno::Sequence<sal_Int8> & rPassHash,const String & sPass)146 void SvPasswordHelper::GetHashPasswordUTF8(uno::Sequence<sal_Int8>& rPassHash, const String& sPass)
147 {
148 const ::rtl::OString aUtf8( ::rtl::OUStringToOString( ::rtl::OUString( sPass ), RTL_TEXTENCODING_UTF8 ) );
149 GetHashPassword(rPassHash, aUtf8.getStr(), aUtf8.getLength());
150 }
151
GetHashPassword(uno::Sequence<sal_Int8> & rPassHash,const String & sPass)152 void SvPasswordHelper::GetHashPassword(uno::Sequence<sal_Int8>& rPassHash, const String& sPass)
153 {
154 GetHashPasswordLittleEndian(rPassHash, sPass);
155 }
156
GetHashPasswordSHA256(uno::Sequence<sal_Int8> & rPassHash,const String & sPass)157 void SvPasswordHelper::GetHashPasswordSHA256(uno::Sequence<sal_Int8>& rPassHash, const String& sPass)
158 {
159 const ::rtl::OString aUtf8( ::rtl::OUStringToOString( ::rtl::OUString( sPass ), RTL_TEXTENCODING_UTF8 ) );
160 rPassHash.realloc(32);
161 lcl_Sha256( reinterpret_cast<const sal_uInt8*>(aUtf8.getStr()), aUtf8.getLength(),
162 reinterpret_cast<sal_uInt8*>(rPassHash.getArray()) );
163 }
164
GetDigestAlgorithmIRI(const uno::Sequence<sal_Int8> & rPassHash)165 ::rtl::OUString SvPasswordHelper::GetDigestAlgorithmIRI(const uno::Sequence<sal_Int8>& rPassHash)
166 {
167 if (rPassHash.getLength() == 32)
168 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "http://www.w3.org/2000/09/xmldsig#sha256" ) );
169 return ::rtl::OUString();
170 }
171
CompareHashPassword(const uno::Sequence<sal_Int8> & rOldPassHash,const String & sNewPass)172 bool SvPasswordHelper::CompareHashPassword(const uno::Sequence<sal_Int8>& rOldPassHash, const String& sNewPass)
173 {
174 uno::Sequence<sal_Int8> aNewPass;
175 if (rOldPassHash.getLength() == 32)
176 {
177 GetHashPasswordSHA256(aNewPass, sNewPass);
178 return aNewPass == rOldPassHash;
179 }
180 if (rOldPassHash.getLength() != RTL_DIGEST_LENGTH_SHA1)
181 return false;
182
183 GetHashPasswordLittleEndian(aNewPass, sNewPass);
184 if (aNewPass == rOldPassHash)
185 return true;
186 GetHashPasswordBigEndian(aNewPass, sNewPass);
187 if (aNewPass == rOldPassHash)
188 return true;
189 GetHashPasswordUTF8(aNewPass, sNewPass);
190 return aNewPass == rOldPassHash;
191 }
192