16df3ef80SGreg Tucker /**********************************************************************
26df3ef80SGreg Tucker Copyright(c) 2011-2016 Intel Corporation All rights reserved.
36df3ef80SGreg Tucker
46df3ef80SGreg Tucker Redistribution and use in source and binary forms, with or without
56df3ef80SGreg Tucker modification, are permitted provided that the following conditions
66df3ef80SGreg Tucker are met:
76df3ef80SGreg Tucker * Redistributions of source code must retain the above copyright
86df3ef80SGreg Tucker notice, this list of conditions and the following disclaimer.
96df3ef80SGreg Tucker * Redistributions in binary form must reproduce the above copyright
106df3ef80SGreg Tucker notice, this list of conditions and the following disclaimer in
116df3ef80SGreg Tucker the documentation and/or other materials provided with the
126df3ef80SGreg Tucker distribution.
136df3ef80SGreg Tucker * Neither the name of Intel Corporation nor the names of its
146df3ef80SGreg Tucker contributors may be used to endorse or promote products derived
156df3ef80SGreg Tucker from this software without specific prior written permission.
166df3ef80SGreg Tucker
176df3ef80SGreg Tucker THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
186df3ef80SGreg Tucker "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
196df3ef80SGreg Tucker LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
206df3ef80SGreg Tucker A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
216df3ef80SGreg Tucker OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
226df3ef80SGreg Tucker SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
236df3ef80SGreg Tucker LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
246df3ef80SGreg Tucker DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
256df3ef80SGreg Tucker THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
266df3ef80SGreg Tucker (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
276df3ef80SGreg Tucker OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
286df3ef80SGreg Tucker **********************************************************************/
296df3ef80SGreg Tucker
3076c9379fSPablo de Lara #include "sha1_mb_internal.h"
316df3ef80SGreg Tucker #include "memcpy_inline.h"
3292aa5aa4SGreg Tucker #include "endian_helper.h"
336df3ef80SGreg Tucker
346df3ef80SGreg Tucker #ifdef _MSC_VER
356df3ef80SGreg Tucker #include <intrin.h>
366df3ef80SGreg Tucker #define inline __inline
376df3ef80SGreg Tucker #endif
386df3ef80SGreg Tucker
39868f05eaSMarcel Cornu static inline void
400106da91SPablo de Lara hash_init_digest(ISAL_SHA1_WORD_T *digest);
41868f05eaSMarcel Cornu static inline uint32_t
420106da91SPablo de Lara hash_pad(uint8_t padblock[ISAL_SHA1_BLOCK_SIZE * 2], uint64_t total_len);
430106da91SPablo de Lara static ISAL_SHA1_HASH_CTX *
440106da91SPablo de Lara sha1_ctx_mgr_resubmit(ISAL_SHA1_HASH_CTX_MGR *mgr, ISAL_SHA1_HASH_CTX *ctx);
456df3ef80SGreg Tucker
46868f05eaSMarcel Cornu void
_sha1_ctx_mgr_init_sse(ISAL_SHA1_HASH_CTX_MGR * mgr)470106da91SPablo de Lara _sha1_ctx_mgr_init_sse(ISAL_SHA1_HASH_CTX_MGR *mgr)
486df3ef80SGreg Tucker {
4976c9379fSPablo de Lara _sha1_mb_mgr_init_sse(&mgr->mgr);
506df3ef80SGreg Tucker }
516df3ef80SGreg Tucker
520106da91SPablo de Lara ISAL_SHA1_HASH_CTX *
_sha1_ctx_mgr_submit_sse(ISAL_SHA1_HASH_CTX_MGR * mgr,ISAL_SHA1_HASH_CTX * ctx,const void * buffer,uint32_t len,ISAL_HASH_CTX_FLAG flags)530106da91SPablo de Lara _sha1_ctx_mgr_submit_sse(ISAL_SHA1_HASH_CTX_MGR *mgr, ISAL_SHA1_HASH_CTX *ctx, const void *buffer,
54*8cb7fe78SPablo de Lara uint32_t len, ISAL_HASH_CTX_FLAG flags)
556df3ef80SGreg Tucker {
56*8cb7fe78SPablo de Lara if (flags & (~ISAL_HASH_ENTIRE)) {
576df3ef80SGreg Tucker // User should not pass anything other than FIRST, UPDATE, or LAST
58*8cb7fe78SPablo de Lara ctx->error = ISAL_HASH_CTX_ERROR_INVALID_FLAGS;
596df3ef80SGreg Tucker return ctx;
606df3ef80SGreg Tucker }
616df3ef80SGreg Tucker
62*8cb7fe78SPablo de Lara if (ctx->status & ISAL_HASH_CTX_STS_PROCESSING) {
636df3ef80SGreg Tucker // Cannot submit to a currently processing job.
64*8cb7fe78SPablo de Lara ctx->error = ISAL_HASH_CTX_ERROR_ALREADY_PROCESSING;
656df3ef80SGreg Tucker return ctx;
666df3ef80SGreg Tucker }
676df3ef80SGreg Tucker
68*8cb7fe78SPablo de Lara if ((ctx->status & ISAL_HASH_CTX_STS_COMPLETE) && !(flags & ISAL_HASH_FIRST)) {
696df3ef80SGreg Tucker // Cannot update a finished job.
70*8cb7fe78SPablo de Lara ctx->error = ISAL_HASH_CTX_ERROR_ALREADY_COMPLETED;
716df3ef80SGreg Tucker return ctx;
726df3ef80SGreg Tucker }
736df3ef80SGreg Tucker
74*8cb7fe78SPablo de Lara if (flags & ISAL_HASH_FIRST) {
756df3ef80SGreg Tucker // Init digest
766df3ef80SGreg Tucker hash_init_digest(ctx->job.result_digest);
776df3ef80SGreg Tucker
786df3ef80SGreg Tucker // Reset byte counter
796df3ef80SGreg Tucker ctx->total_length = 0;
806df3ef80SGreg Tucker
816df3ef80SGreg Tucker // Clear extra blocks
826df3ef80SGreg Tucker ctx->partial_block_buffer_length = 0;
836df3ef80SGreg Tucker }
846df3ef80SGreg Tucker // If we made it here, there were no errors during this call to submit
85*8cb7fe78SPablo de Lara ctx->error = ISAL_HASH_CTX_ERROR_NONE;
866df3ef80SGreg Tucker
876df3ef80SGreg Tucker // Store buffer ptr info from user
886df3ef80SGreg Tucker ctx->incoming_buffer = buffer;
896df3ef80SGreg Tucker ctx->incoming_buffer_length = len;
906df3ef80SGreg Tucker
916df3ef80SGreg Tucker // Store the user's request flags and mark this ctx as currently being processed.
92*8cb7fe78SPablo de Lara ctx->status = (flags & ISAL_HASH_LAST) ? (ISAL_HASH_CTX_STS) (ISAL_HASH_CTX_STS_PROCESSING |
93*8cb7fe78SPablo de Lara ISAL_HASH_CTX_STS_LAST)
94*8cb7fe78SPablo de Lara : ISAL_HASH_CTX_STS_PROCESSING;
956df3ef80SGreg Tucker
966df3ef80SGreg Tucker // Advance byte counter
976df3ef80SGreg Tucker ctx->total_length += len;
986df3ef80SGreg Tucker
99868f05eaSMarcel Cornu // If there is anything currently buffered in the extra blocks, append to it until it
100868f05eaSMarcel Cornu // contains a whole block. Or if the user's buffer contains less than a whole block, append
101868f05eaSMarcel Cornu // as much as possible to the extra block.
1020106da91SPablo de Lara if ((ctx->partial_block_buffer_length) | (len < ISAL_SHA1_BLOCK_SIZE)) {
1036df3ef80SGreg Tucker // Compute how many bytes to copy from user buffer into extra block
1040106da91SPablo de Lara uint32_t copy_len = ISAL_SHA1_BLOCK_SIZE - ctx->partial_block_buffer_length;
1056df3ef80SGreg Tucker if (len < copy_len)
1066df3ef80SGreg Tucker copy_len = len;
1076df3ef80SGreg Tucker
1086df3ef80SGreg Tucker if (copy_len) {
1096df3ef80SGreg Tucker // Copy and update relevant pointers and counters
110868f05eaSMarcel Cornu memcpy_varlen(&ctx->partial_block_buffer[ctx->partial_block_buffer_length],
111868f05eaSMarcel Cornu buffer, copy_len);
1126df3ef80SGreg Tucker
1136df3ef80SGreg Tucker ctx->partial_block_buffer_length += copy_len;
1146df3ef80SGreg Tucker ctx->incoming_buffer = (const void *) ((const char *) buffer + copy_len);
1156df3ef80SGreg Tucker ctx->incoming_buffer_length = len - copy_len;
1166df3ef80SGreg Tucker }
1176df3ef80SGreg Tucker // The extra block should never contain more than 1 block here
1180106da91SPablo de Lara assert(ctx->partial_block_buffer_length <= ISAL_SHA1_BLOCK_SIZE);
1196df3ef80SGreg Tucker
1206df3ef80SGreg Tucker // If the extra block buffer contains exactly 1 block, it can be hashed.
1210106da91SPablo de Lara if (ctx->partial_block_buffer_length >= ISAL_SHA1_BLOCK_SIZE) {
1226df3ef80SGreg Tucker ctx->partial_block_buffer_length = 0;
1236df3ef80SGreg Tucker
1246df3ef80SGreg Tucker ctx->job.buffer = ctx->partial_block_buffer;
1256df3ef80SGreg Tucker ctx->job.len = 1;
1266df3ef80SGreg Tucker
1270106da91SPablo de Lara ctx = (ISAL_SHA1_HASH_CTX *) _sha1_mb_mgr_submit_sse(&mgr->mgr, &ctx->job);
1286df3ef80SGreg Tucker }
1296df3ef80SGreg Tucker }
1306df3ef80SGreg Tucker
1316df3ef80SGreg Tucker return sha1_ctx_mgr_resubmit(mgr, ctx);
1326df3ef80SGreg Tucker }
1336df3ef80SGreg Tucker
1340106da91SPablo de Lara ISAL_SHA1_HASH_CTX *
_sha1_ctx_mgr_flush_sse(ISAL_SHA1_HASH_CTX_MGR * mgr)1350106da91SPablo de Lara _sha1_ctx_mgr_flush_sse(ISAL_SHA1_HASH_CTX_MGR *mgr)
1366df3ef80SGreg Tucker {
1370106da91SPablo de Lara ISAL_SHA1_HASH_CTX *ctx;
1386df3ef80SGreg Tucker
1396df3ef80SGreg Tucker while (1) {
1400106da91SPablo de Lara ctx = (ISAL_SHA1_HASH_CTX *) _sha1_mb_mgr_flush_sse(&mgr->mgr);
1416df3ef80SGreg Tucker
1426df3ef80SGreg Tucker // If flush returned 0, there are no more jobs in flight.
1436df3ef80SGreg Tucker if (!ctx)
1446df3ef80SGreg Tucker return NULL;
1456df3ef80SGreg Tucker
1466df3ef80SGreg Tucker // If flush returned a job, verify that it is safe to return to the user.
1476df3ef80SGreg Tucker // If it is not ready, resubmit the job to finish processing.
1486df3ef80SGreg Tucker ctx = sha1_ctx_mgr_resubmit(mgr, ctx);
1496df3ef80SGreg Tucker
1506df3ef80SGreg Tucker // If sha1_ctx_mgr_resubmit returned a job, it is ready to be returned.
1516df3ef80SGreg Tucker if (ctx)
1526df3ef80SGreg Tucker return ctx;
1536df3ef80SGreg Tucker
1540106da91SPablo de Lara // Otherwise, all jobs currently being managed by the ISAL_SHA1_HASH_CTX_MGR still
1550106da91SPablo de Lara // need processing. Loop.
1566df3ef80SGreg Tucker }
1576df3ef80SGreg Tucker }
1586df3ef80SGreg Tucker
1590106da91SPablo de Lara static ISAL_SHA1_HASH_CTX *
sha1_ctx_mgr_resubmit(ISAL_SHA1_HASH_CTX_MGR * mgr,ISAL_SHA1_HASH_CTX * ctx)1600106da91SPablo de Lara sha1_ctx_mgr_resubmit(ISAL_SHA1_HASH_CTX_MGR *mgr, ISAL_SHA1_HASH_CTX *ctx)
1616df3ef80SGreg Tucker {
1626df3ef80SGreg Tucker while (ctx) {
1636df3ef80SGreg Tucker
164*8cb7fe78SPablo de Lara if (ctx->status & ISAL_HASH_CTX_STS_COMPLETE) {
165*8cb7fe78SPablo de Lara ctx->status = ISAL_HASH_CTX_STS_COMPLETE; // Clear PROCESSING bit
1666df3ef80SGreg Tucker return ctx;
1676df3ef80SGreg Tucker }
1686df3ef80SGreg Tucker // If the extra blocks are empty, begin hashing what remains in the user's buffer.
1696df3ef80SGreg Tucker if (ctx->partial_block_buffer_length == 0 && ctx->incoming_buffer_length) {
1706df3ef80SGreg Tucker const void *buffer = ctx->incoming_buffer;
1716df3ef80SGreg Tucker uint32_t len = ctx->incoming_buffer_length;
1726df3ef80SGreg Tucker
1736df3ef80SGreg Tucker // Only entire blocks can be hashed. Copy remainder to extra blocks buffer.
1740106da91SPablo de Lara uint32_t copy_len = len & (ISAL_SHA1_BLOCK_SIZE - 1);
1756df3ef80SGreg Tucker
1766df3ef80SGreg Tucker if (copy_len) {
1776df3ef80SGreg Tucker len -= copy_len;
1786df3ef80SGreg Tucker memcpy_varlen(ctx->partial_block_buffer,
1796df3ef80SGreg Tucker ((const char *) buffer + len), copy_len);
1806df3ef80SGreg Tucker ctx->partial_block_buffer_length = copy_len;
1816df3ef80SGreg Tucker }
1826df3ef80SGreg Tucker
1836df3ef80SGreg Tucker ctx->incoming_buffer_length = 0;
1846df3ef80SGreg Tucker
1856df3ef80SGreg Tucker // len should be a multiple of the block size now
1860106da91SPablo de Lara assert((len % ISAL_SHA1_BLOCK_SIZE) == 0);
1876df3ef80SGreg Tucker
1886df3ef80SGreg Tucker // Set len to the number of blocks to be hashed in the user's buffer
1890106da91SPablo de Lara len >>= ISAL_SHA1_LOG2_BLOCK_SIZE;
1906df3ef80SGreg Tucker
1916df3ef80SGreg Tucker if (len) {
1926df3ef80SGreg Tucker ctx->job.buffer = (uint8_t *) buffer;
1936df3ef80SGreg Tucker ctx->job.len = len;
1940106da91SPablo de Lara ctx = (ISAL_SHA1_HASH_CTX *) _sha1_mb_mgr_submit_sse(&mgr->mgr,
1956df3ef80SGreg Tucker &ctx->job);
1966df3ef80SGreg Tucker continue;
1976df3ef80SGreg Tucker }
1986df3ef80SGreg Tucker }
1996df3ef80SGreg Tucker // If the extra blocks are not empty, then we are either on the last block(s)
2006df3ef80SGreg Tucker // or we need more user input before continuing.
201*8cb7fe78SPablo de Lara if (ctx->status & ISAL_HASH_CTX_STS_LAST) {
2026df3ef80SGreg Tucker uint8_t *buf = ctx->partial_block_buffer;
2036df3ef80SGreg Tucker uint32_t n_extra_blocks = hash_pad(buf, ctx->total_length);
2046df3ef80SGreg Tucker
205*8cb7fe78SPablo de Lara ctx->status = (ISAL_HASH_CTX_STS) (ISAL_HASH_CTX_STS_PROCESSING |
206*8cb7fe78SPablo de Lara ISAL_HASH_CTX_STS_COMPLETE);
2076df3ef80SGreg Tucker ctx->job.buffer = buf;
2086df3ef80SGreg Tucker ctx->job.len = (uint32_t) n_extra_blocks;
2090106da91SPablo de Lara ctx = (ISAL_SHA1_HASH_CTX *) _sha1_mb_mgr_submit_sse(&mgr->mgr, &ctx->job);
2106df3ef80SGreg Tucker continue;
2116df3ef80SGreg Tucker }
2126df3ef80SGreg Tucker
2136df3ef80SGreg Tucker if (ctx)
214*8cb7fe78SPablo de Lara ctx->status = ISAL_HASH_CTX_STS_IDLE;
2156df3ef80SGreg Tucker return ctx;
2166df3ef80SGreg Tucker }
2176df3ef80SGreg Tucker
2186df3ef80SGreg Tucker return NULL;
2196df3ef80SGreg Tucker }
2206df3ef80SGreg Tucker
221868f05eaSMarcel Cornu static inline void
hash_init_digest(ISAL_SHA1_WORD_T * digest)2220106da91SPablo de Lara hash_init_digest(ISAL_SHA1_WORD_T *digest)
2236df3ef80SGreg Tucker {
2240106da91SPablo de Lara static const ISAL_SHA1_WORD_T hash_initial_digest[ISAL_SHA1_DIGEST_NWORDS] = {
2250106da91SPablo de Lara ISAL_SHA1_INITIAL_DIGEST
2260106da91SPablo de Lara };
2276df3ef80SGreg Tucker memcpy_fixedlen(digest, hash_initial_digest, sizeof(hash_initial_digest));
2286df3ef80SGreg Tucker }
2296df3ef80SGreg Tucker
230868f05eaSMarcel Cornu static inline uint32_t
hash_pad(uint8_t padblock[ISAL_SHA1_BLOCK_SIZE * 2],uint64_t total_len)2310106da91SPablo de Lara hash_pad(uint8_t padblock[ISAL_SHA1_BLOCK_SIZE * 2], uint64_t total_len)
2326df3ef80SGreg Tucker {
2330106da91SPablo de Lara uint32_t i = (uint32_t) (total_len & (ISAL_SHA1_BLOCK_SIZE - 1));
2346df3ef80SGreg Tucker
2350106da91SPablo de Lara memclr_fixedlen(&padblock[i], ISAL_SHA1_BLOCK_SIZE);
2366df3ef80SGreg Tucker padblock[i] = 0x80;
2376df3ef80SGreg Tucker
2386df3ef80SGreg Tucker // Move i to the end of either 1st or 2nd extra block depending on length
2390106da91SPablo de Lara i += ((ISAL_SHA1_BLOCK_SIZE - 1) & (0 - (total_len + ISAL_SHA1_PADLENGTHFIELD_SIZE + 1))) +
2400106da91SPablo de Lara 1 + ISAL_SHA1_PADLENGTHFIELD_SIZE;
2416df3ef80SGreg Tucker
2420106da91SPablo de Lara #if ISAL_SHA1_PADLENGTHFIELD_SIZE == 16
2436df3ef80SGreg Tucker *((uint64_t *) &padblock[i - 16]) = 0;
2446df3ef80SGreg Tucker #endif
2456df3ef80SGreg Tucker
246e3f7d4fbSUlrich Weigand *((uint64_t *) &padblock[i - 8]) = to_be64((uint64_t) total_len << 3);
2476df3ef80SGreg Tucker
2480106da91SPablo de Lara return i >> ISAL_SHA1_LOG2_BLOCK_SIZE; // Number of extra blocks to hash
2496df3ef80SGreg Tucker }
2506df3ef80SGreg Tucker
2516df3ef80SGreg Tucker struct slver {
2526df3ef80SGreg Tucker uint16_t snum;
2536df3ef80SGreg Tucker uint8_t ver;
2546df3ef80SGreg Tucker uint8_t core;
2556df3ef80SGreg Tucker };
2563113c339SPablo de Lara struct slver _sha1_ctx_mgr_init_sse_slver_00020139;
2573113c339SPablo de Lara struct slver _sha1_ctx_mgr_init_sse_slver = { 0x0139, 0x02, 0x00 };
2586df3ef80SGreg Tucker
2593113c339SPablo de Lara struct slver _sha1_ctx_mgr_submit_sse_slver_00020140;
2603113c339SPablo de Lara struct slver _sha1_ctx_mgr_submit_sse_slver = { 0x0140, 0x02, 0x00 };
2616df3ef80SGreg Tucker
2623113c339SPablo de Lara struct slver _sha1_ctx_mgr_flush_sse_slver_00020141;
2633113c339SPablo de Lara struct slver _sha1_ctx_mgr_flush_sse_slver = { 0x0141, 0x02, 0x00 };
264