xref: /trunk/main/svl/source/misc/PasswordHelper.cxx (revision d666495c4f609ab94ddded8b0141831070b22d11)
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