/* $NetBSD: mvcesa.c,v 1.6 2022/05/22 11:39:27 riastradh Exp $ */
/*
* Copyright (c) 2008 KIYOHARA Takashi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
count = 0;
enc = mac = 0;
for (c = cri; c != NULL; c = c->cri_next) {
switch (c->cri_alg) {
case CRYPTO_DES_CBC:
case CRYPTO_3DES_CBC:
if (enc)
return EINVAL;
enc = 1;
/* Go ahead and compute key in CESA's byte order */
ses->ses_klen = c->cri_klen;
memcpy(ses->ses_key, c->cri_key, c->cri_klen / 8);
switch (c->cri_alg) {
case CRYPTO_3DES_CBC:
ses->ses_key[5] = htobe32(ses->ses_key[5]);
ses->ses_key[4] = htobe32(ses->ses_key[4]);
ses->ses_key[3] = htobe32(ses->ses_key[3]);
ses->ses_key[2] = htobe32(ses->ses_key[2]);
if (iv != NULL)
bus_space_write_region_4(sc->sc_iot, sc->sc_ioh,
MVCESA_SHA1MD5I_IVDA, iv, dlen / 4);
off = i = 0;
while (1 /* CONSTCOND */) {
data = 0;
if (buf != NULL)
for (i = 0; i < 512 / 8 && off + i < len; i += s) {
s = uimin(sizeof(data), len - off - i);
memcpy(&data, buf + skip + off + i, s);
if (s == sizeof(data))
bus_space_write_4(sc->sc_iot,
sc->sc_ioh, MVCESA_SHA1MD5I_DI,
data);
}
else if (m != NULL)
for (i = 0; i < 512 / 8 && off + i < len; i += s) {
s = uimin(sizeof(data), len - off - i);
m_copydata(m, skip + off + i, s, &data);
if (s == sizeof(data))
bus_space_write_4(sc->sc_iot,
sc->sc_ioh, MVCESA_SHA1MD5I_DI,
data);
}
else if (uio != NULL)
for (i = 0; i < 512 / 8 && off + i < len; i += s) {
s = uimin(sizeof(data), len - off - i);
cuio_copydata(uio, skip + off + i, s, &data);
if (s == sizeof(data))
bus_space_write_4(sc->sc_iot,
sc->sc_ioh, MVCESA_SHA1MD5I_DI,
data);
}
off += i;
if (i < 512 / 8)
break;
do {
cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
MVCESA_SHA1MD5I_AC);
} while (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION));
if (i < 512 / 8) {
*((char *)&data + (i % 4)) = 0x80;
bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_DI,
data);
i = (i & ~3) + 4;
/* Do pad to 512 bits, if chunk size is more than 448 bits. */
if (i > 448 / 8) {
for (; i < 512 / 8; i += 4)
bus_space_write_4(sc->sc_iot, sc->sc_ioh,
MVCESA_SHA1MD5I_DI, 0);
do {
cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
MVCESA_SHA1MD5I_AC);
} while (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION));
i = 0;
}
for (; i < 448 / 8; i += 4)
bus_space_write_4(sc->sc_iot, sc->sc_ioh,
MVCESA_SHA1MD5I_DI, 0);
/* Set total bits */
bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_BCL,
bits & 0xffffffff);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_BCH,
bits >> 32);
do {
cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
MVCESA_SHA1MD5I_AC);
} while (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION));
}
if (digest != NULL) {
/* Read digest */
bus_space_read_region_4(sc->sc_iot, sc->sc_ioh,
MVCESA_SHA1MD5I_IVDA, digest, dlen / 8 / 4);
#if BYTE_ORDER == LITTLE_ENDIAN
if (alg == MVCESA_SHA1MD5I_AC_ALGORITHM_SHA1)
for (i = 0; i < dlen / 8 / 4; i++)
digest[i] = be32toh(digest[i]);
#else
if (alg == MVCESA_SHA1MD5I_AC_ALGORITHM_MD5)
for (i = 0; i < dlen / 8 / 4; i++)
digest[i] = le32toh(digest[i]);
#endif
}
return 0;
}
static int
mvcesa_des_encdec(struct mvcesa_softc *sc, struct mvcesa_session *ses,
uint32_t alg, uint32_t mode, uint32_t dir, uint32_t *iv,
int skip, int len, char *buf, struct mbuf *m, struct uio *uio)
{
uint64_t iblk, oblk;
uint32_t cmd, bswp = 0;
int i, o, s;
if (cmd & MVCESA_DESE_C_ALLTERMINATION) {
/* We can read IV from Data Out Registers. */
if (dir == MVCESA_DESE_C_DIRECTION_ENC)
o -= sizeof(oblk);
else
break;
}
if (buf != NULL)
memcpy(buf + skip + o, &oblk, sizeof(oblk));
else if (m != NULL)
m_copydata(m, skip + o, sizeof(oblk), &oblk);
else if (uio != NULL)
cuio_copyback(uio, skip + o, sizeof(oblk),
&oblk);
o += sizeof(oblk);
if (cmd & MVCESA_DESE_C_ALLTERMINATION)
break;
}
}