| /* Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "SHA1MessageDigestSpi.h" |
| |
| #ifdef HAVE_STRING_H |
| #include <string.h> |
| #endif |
| |
| #include <decaf/lang/System.h> |
| #include <decaf/security/DigestException.h> |
| |
| using namespace decaf; |
| using namespace decaf::lang; |
| using namespace decaf::security; |
| using namespace decaf::internal; |
| using namespace decaf::internal::security; |
| using namespace decaf::internal::security::provider; |
| using namespace decaf::internal::security::provider::crypto; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| namespace { |
| |
| #define DECAF_SHA1_DIGESTSIZE 20 |
| |
| /* SHA f()-functions */ |
| #define f1(x,y,z) ((x & y) | (~x & z)) |
| #define f2(x,y,z) (x ^ y ^ z) |
| #define f3(x,y,z) ((x & y) | (x & z) | (y & z)) |
| #define f4(x,y,z) (x ^ y ^ z) |
| |
| // SHA constants |
| #define CONST1 0x5a827999 |
| #define CONST2 0x6ed9eba1 |
| #define CONST3 0x8f1bbcdc |
| #define CONST4 0xca62c1d6 |
| |
| // 32-bit rotate |
| #define ROT32(x,n) ((x << n) | (x >> (32 - n))) |
| |
| #define FUNC(n,i) \ |
| temp = ROT32(A,5) + f##n(B,C,D) + E + W[i] + CONST##n; \ |
| E = D; D = C; C = ROT32(B,30); B = A; A = temp |
| |
| #define SHA_BLOCKSIZE 64 |
| |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| namespace decaf { |
| namespace internal { |
| namespace security { |
| namespace provider { |
| namespace crypto { |
| |
| class SHA1MessageDigestSpiImpl { |
| public: |
| |
| // message digest |
| unsigned int state[5]; |
| // 64-bit bit counts |
| unsigned int count[2]; |
| // SHA data buffer |
| unsigned int data[16]; |
| // unprocessed amount in data form last update |
| int local; |
| |
| private: |
| |
| union endianTest { |
| long Long; |
| char Char[sizeof(long)]; |
| }; |
| |
| static bool isLittleEndian() { |
| static union endianTest u; |
| u.Long = 1; |
| return (u.Char[0] == 1); |
| } |
| |
| static void maybeReverseBytes(unsigned int* buffer, int count) { |
| |
| int i; |
| unsigned char ct[4], *cp; |
| |
| if (isLittleEndian()) { // do the swap only if it is little endian |
| count = (int)(count / 4); |
| cp = (unsigned char*) buffer; |
| for (i = 0; i < count; ++i) { |
| ct[0] = cp[0]; |
| ct[1] = cp[1]; |
| ct[2] = cp[2]; |
| ct[3] = cp[3]; |
| cp[0] = ct[3]; |
| cp[1] = ct[2]; |
| cp[2] = ct[1]; |
| cp[3] = ct[0]; |
| cp += sizeof(int); |
| } |
| } |
| } |
| |
| static void SHA1Transform(unsigned int state[5], const unsigned int buffer[16]) { |
| int i; |
| unsigned int temp, A, B, C, D, E, W[80]; |
| |
| for (i = 0; i < 16; ++i) { |
| W[i] = buffer[i]; |
| } |
| for (i = 16; i < 80; ++i) { |
| W[i] = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]; |
| } |
| A = state[0]; |
| B = state[1]; |
| C = state[2]; |
| D = state[3]; |
| E = state[4]; |
| |
| FUNC(1, 0); FUNC(1, 1); FUNC(1, 2); FUNC(1, 3); FUNC(1, 4); |
| FUNC(1, 5); FUNC(1, 6); FUNC(1, 7); FUNC(1, 8); FUNC(1, 9); |
| FUNC(1,10); FUNC(1,11); FUNC(1,12); FUNC(1,13); FUNC(1,14); |
| FUNC(1,15); FUNC(1,16); FUNC(1,17); FUNC(1,18); FUNC(1,19); |
| |
| FUNC(2,20); FUNC(2,21); FUNC(2,22); FUNC(2,23); FUNC(2,24); |
| FUNC(2,25); FUNC(2,26); FUNC(2,27); FUNC(2,28); FUNC(2,29); |
| FUNC(2,30); FUNC(2,31); FUNC(2,32); FUNC(2,33); FUNC(2,34); |
| FUNC(2,35); FUNC(2,36); FUNC(2,37); FUNC(2,38); FUNC(2,39); |
| |
| FUNC(3,40); FUNC(3,41); FUNC(3,42); FUNC(3,43); FUNC(3,44); |
| FUNC(3,45); FUNC(3,46); FUNC(3,47); FUNC(3,48); FUNC(3,49); |
| FUNC(3,50); FUNC(3,51); FUNC(3,52); FUNC(3,53); FUNC(3,54); |
| FUNC(3,55); FUNC(3,56); FUNC(3,57); FUNC(3,58); FUNC(3,59); |
| |
| FUNC(4,60); FUNC(4,61); FUNC(4,62); FUNC(4,63); FUNC(4,64); |
| FUNC(4,65); FUNC(4,66); FUNC(4,67); FUNC(4,68); FUNC(4,69); |
| FUNC(4,70); FUNC(4,71); FUNC(4,72); FUNC(4,73); FUNC(4,74); |
| FUNC(4,75); FUNC(4,76); FUNC(4,77); FUNC(4,78); FUNC(4,79); |
| |
| state[0] += A; |
| state[1] += B; |
| state[2] += C; |
| state[3] += D; |
| state[4] += E; |
| } |
| |
| public: |
| |
| SHA1MessageDigestSpiImpl() : state(), count(), data(), local() { |
| reset(); |
| } |
| |
| void reset() { |
| state[0] = 0x67452301; |
| state[1] = 0xefcdab89; |
| state[2] = 0x98badcfe; |
| state[3] = 0x10325476; |
| state[4] = 0xc3d2e1f0; |
| count[0] = 0; |
| count[0] = 0; |
| local = 0; |
| } |
| |
| void update(const unsigned char* input, int length) { |
| int i; |
| |
| if ((count[0] + ((unsigned int) length << 3)) < count[0]) { |
| ++count[1]; |
| } |
| count[0] += (unsigned int) length << 3; |
| count[1] += (unsigned int) length >> 29; |
| if (local) { |
| i = SHA_BLOCKSIZE - local; |
| if (i > length) { |
| i = length; |
| } |
| memcpy(((unsigned char*) data) + local, input, i); |
| |
| length -= i; |
| input += i; |
| local += i; |
| |
| if (local == SHA_BLOCKSIZE) { |
| maybeReverseBytes(data, SHA_BLOCKSIZE); |
| SHA1Transform(state, data); |
| } else { |
| return; |
| } |
| } |
| |
| while (length >= SHA_BLOCKSIZE) { |
| memcpy(data, input, SHA_BLOCKSIZE); |
| input += SHA_BLOCKSIZE; |
| length -= SHA_BLOCKSIZE; |
| maybeReverseBytes(data, SHA_BLOCKSIZE); |
| SHA1Transform(state, data); |
| } |
| memcpy(data, input, length); |
| local = length; |
| } |
| |
| void finalize(unsigned char digest[DECAF_SHA1_DIGESTSIZE]) { |
| int index, i, j; |
| unsigned int lo_bit_count, hi_bit_count, k; |
| |
| lo_bit_count = count[0]; |
| hi_bit_count = count[1]; |
| index = (int) ((lo_bit_count >> 3) & 0x3f); |
| ((unsigned char*) data)[index++] = 0x80; |
| |
| if (index > SHA_BLOCKSIZE - 8) { |
| memset(((unsigned char*) data) + index, 0, SHA_BLOCKSIZE - index); |
| maybeReverseBytes(data, SHA_BLOCKSIZE); |
| SHA1Transform(state, data); |
| memset((unsigned char*) data, 0, SHA_BLOCKSIZE - 8); |
| } else { |
| memset(((unsigned char*) data) + index, 0, SHA_BLOCKSIZE - 8 - index); |
| } |
| |
| maybeReverseBytes(data, SHA_BLOCKSIZE); |
| data[14] = hi_bit_count; |
| data[15] = lo_bit_count; |
| SHA1Transform(state, data); |
| |
| for (i = 0, j = 0; j < DECAF_SHA1_DIGESTSIZE; i++) { |
| k = state[i]; |
| digest[j++] = (unsigned char) ((k >> 24) & 0xff); |
| digest[j++] = (unsigned char) ((k >> 16) & 0xff); |
| digest[j++] = (unsigned char) ((k >> 8) & 0xff); |
| digest[j++] = (unsigned char) (k & 0xff); |
| } |
| } |
| }; |
| |
| }}}}} |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| SHA1MessageDigestSpi::SHA1MessageDigestSpi() : MessageDigestSpi(), impl(new SHA1MessageDigestSpiImpl) { |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| SHA1MessageDigestSpi::~SHA1MessageDigestSpi() { |
| delete this->impl; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| MessageDigestSpi* SHA1MessageDigestSpi::clone() { |
| SHA1MessageDigestSpi* clone = new SHA1MessageDigestSpi; |
| |
| System::arraycopy(clone->impl->state, 0, this->impl->state, 0, 5); |
| System::arraycopy(clone->impl->count, 0, this->impl->count, 0, 2); |
| System::arraycopy(clone->impl->data, 0, this->impl->data, 0, 16); |
| clone->impl->local = this->impl->local; |
| |
| return clone; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| int SHA1MessageDigestSpi::engineGetDigestLength() { |
| return DECAF_SHA1_DIGESTSIZE; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| void SHA1MessageDigestSpi::engineUpdate(unsigned char input) { |
| this->impl->update(&input, 1); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| void SHA1MessageDigestSpi::engineUpdate(const unsigned char* input, int size, int offset, int length) { |
| |
| if (input == NULL && size > 0) { |
| throw DigestException(__FILE__, __LINE__, "Null buffer parameter."); |
| } |
| |
| if (size <= 0) { |
| return; |
| } |
| |
| if (offset < 0 || length < 0) { |
| engineReset(); |
| throw DigestException(__FILE__, __LINE__, "Incorrect offset or length value."); |
| } |
| |
| if (offset + length > size) { |
| engineReset(); |
| throw DigestException(__FILE__, __LINE__, "Incorrect offset or length value."); |
| } |
| |
| this->impl->update(&input[offset], length); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| void SHA1MessageDigestSpi::engineUpdate(const std::vector<unsigned char>& input) { |
| |
| if (input.empty()) { |
| return; |
| } |
| |
| this->impl->update(&input[0], (int)input.size()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| void SHA1MessageDigestSpi::engineUpdate(decaf::nio::ByteBuffer& input) { |
| |
| if (!input.hasRemaining()) { |
| return; |
| } |
| unsigned char* temp; |
| if (input.hasArray()) { |
| temp = input.array(); |
| int offset = input.arrayOffset(); |
| int position = input.position(); |
| int limit = input.limit(); |
| engineUpdate(temp, limit - position, offset + position, limit - position); |
| input.position(limit); |
| } else { |
| int length = input.limit() - input.position(); |
| temp = new unsigned char[length]; |
| input.get(temp, length, 0, length); |
| engineUpdate(temp, length, 0, length); |
| delete [] temp; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| void SHA1MessageDigestSpi::engineReset() { |
| this->impl->reset(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| std::vector<unsigned char> SHA1MessageDigestSpi::engineDigest() { |
| |
| std::vector<unsigned char> buffer; |
| buffer.resize(DECAF_SHA1_DIGESTSIZE); |
| this->impl->finalize(&buffer[0]); |
| |
| return buffer; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| int SHA1MessageDigestSpi::engineDigest(unsigned char* buffer, int size, int offset, int length) { |
| |
| if (buffer == NULL) { |
| engineReset(); |
| throw DigestException(__FILE__, __LINE__, "Null buffer parameter."); |
| } |
| |
| if (size < engineGetDigestLength()) { |
| engineReset(); |
| throw DigestException(__FILE__, __LINE__, |
| "The value of size parameter is less than the actual digest length."); |
| } |
| |
| if (length < engineGetDigestLength()) { |
| engineReset(); |
| throw DigestException(__FILE__, __LINE__, |
| "The value of length parameter is less than the actual digest length."); |
| } |
| |
| if (offset < 0) { |
| engineReset(); |
| throw DigestException(__FILE__, __LINE__, "Invalid negative offset."); |
| } |
| |
| if (offset + length > size) { |
| engineReset(); |
| throw DigestException(__FILE__, __LINE__, "Incorrect offset or length value."); |
| } |
| |
| std::vector<unsigned char> temp = engineDigest(); |
| if (length < (int)temp.size()) { |
| throw DigestException(__FILE__, __LINE__, |
| "The value of length parameter is less than the actual digest length.."); |
| } |
| |
| System::arraycopy(&temp[0], 0, buffer, offset, temp.size()); |
| return (int)temp.size(); |
| } |