1eaa3b919SPawel Jakub Dawidek /*- 23728855aSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 33728855aSPedro F. Giffuni * 41e09ff3dSPawel Jakub Dawidek * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net> 5eaa3b919SPawel Jakub Dawidek * All rights reserved. 6eaa3b919SPawel Jakub Dawidek * 7eaa3b919SPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 8eaa3b919SPawel Jakub Dawidek * modification, are permitted provided that the following conditions 9eaa3b919SPawel Jakub Dawidek * are met: 10eaa3b919SPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 11eaa3b919SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 12eaa3b919SPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 13eaa3b919SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 14eaa3b919SPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 15eaa3b919SPawel Jakub Dawidek * 16eaa3b919SPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17eaa3b919SPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18eaa3b919SPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19eaa3b919SPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20eaa3b919SPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21eaa3b919SPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22eaa3b919SPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23eaa3b919SPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24eaa3b919SPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25eaa3b919SPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26eaa3b919SPawel Jakub Dawidek * SUCH DAMAGE. 27eaa3b919SPawel Jakub Dawidek */ 28eaa3b919SPawel Jakub Dawidek 29eaa3b919SPawel Jakub Dawidek #include <sys/cdefs.h> 30eaa3b919SPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 31eaa3b919SPawel Jakub Dawidek 32eaa3b919SPawel Jakub Dawidek #include <sys/param.h> 33eaa3b919SPawel Jakub Dawidek #include <sys/systm.h> 34eaa3b919SPawel Jakub Dawidek #include <sys/kernel.h> 35eaa3b919SPawel Jakub Dawidek #include <sys/linker.h> 36eaa3b919SPawel Jakub Dawidek #include <sys/module.h> 37eaa3b919SPawel Jakub Dawidek #include <sys/lock.h> 38eaa3b919SPawel Jakub Dawidek #include <sys/mutex.h> 39eaa3b919SPawel Jakub Dawidek #include <sys/bio.h> 40eaa3b919SPawel Jakub Dawidek #include <sys/sysctl.h> 41eaa3b919SPawel Jakub Dawidek #include <sys/malloc.h> 42eaa3b919SPawel Jakub Dawidek #include <sys/kthread.h> 43eaa3b919SPawel Jakub Dawidek #include <sys/proc.h> 44eaa3b919SPawel Jakub Dawidek #include <sys/sched.h> 45eaa3b919SPawel Jakub Dawidek #include <sys/smp.h> 46eaa3b919SPawel Jakub Dawidek #include <sys/vnode.h> 47eaa3b919SPawel Jakub Dawidek 48eaa3b919SPawel Jakub Dawidek #include <vm/uma.h> 49eaa3b919SPawel Jakub Dawidek 50eaa3b919SPawel Jakub Dawidek #include <geom/geom.h> 51ac03832eSConrad Meyer #include <geom/geom_dbg.h> 52eaa3b919SPawel Jakub Dawidek #include <geom/eli/g_eli.h> 53eaa3b919SPawel Jakub Dawidek #include <geom/eli/pkcs5v2.h> 54eaa3b919SPawel Jakub Dawidek 55eaa3b919SPawel Jakub Dawidek /* 56eaa3b919SPawel Jakub Dawidek * The data layout description when integrity verification is configured. 57eaa3b919SPawel Jakub Dawidek * 58eaa3b919SPawel Jakub Dawidek * One of the most important assumption here is that authenticated data and its 59eaa3b919SPawel Jakub Dawidek * HMAC has to be stored in the same place (namely in the same sector) to make 60eaa3b919SPawel Jakub Dawidek * it work reliable. 61eaa3b919SPawel Jakub Dawidek * The problem is that file systems work only with sectors that are multiple of 62eaa3b919SPawel Jakub Dawidek * 512 bytes and a power of two number. 63eaa3b919SPawel Jakub Dawidek * My idea to implement it is as follows. 64eaa3b919SPawel Jakub Dawidek * Let's store HMAC in sector. This is a must. This leaves us 480 bytes for 65eaa3b919SPawel Jakub Dawidek * data. We can't use that directly (ie. we can't create provider with 480 bytes 66eaa3b919SPawel Jakub Dawidek * sector size). We need another sector from where we take only 32 bytes of data 67eaa3b919SPawel Jakub Dawidek * and we store HMAC of this data as well. This takes two sectors from the 68eaa3b919SPawel Jakub Dawidek * original provider at the input and leaves us one sector of authenticated data 69eaa3b919SPawel Jakub Dawidek * at the output. Not very efficient, but you got the idea. 70eaa3b919SPawel Jakub Dawidek * Now, let's assume, we want to create provider with 4096 bytes sector. 71eaa3b919SPawel Jakub Dawidek * To output 4096 bytes of authenticated data we need 8x480 plus 1x256, so we 72eaa3b919SPawel Jakub Dawidek * need nine 512-bytes sectors at the input to get one 4096-bytes sector at the 73eaa3b919SPawel Jakub Dawidek * output. That's better. With 4096 bytes sector we can use 89% of size of the 74eaa3b919SPawel Jakub Dawidek * original provider. I find it as an acceptable cost. 75eaa3b919SPawel Jakub Dawidek * The reliability comes from the fact, that every HMAC stored inside the sector 76eaa3b919SPawel Jakub Dawidek * is calculated only for the data in the same sector, so its impossible to 77eaa3b919SPawel Jakub Dawidek * write new data and leave old HMAC or vice versa. 78eaa3b919SPawel Jakub Dawidek * 79eaa3b919SPawel Jakub Dawidek * And here is the picture: 80eaa3b919SPawel Jakub Dawidek * 81eaa3b919SPawel Jakub Dawidek * da0: +----+----+ +----+----+ +----+----+ +----+----+ +----+----+ +----+----+ +----+----+ +----+----+ +----+-----+ 82eaa3b919SPawel Jakub Dawidek * |32b |480b| |32b |480b| |32b |480b| |32b |480b| |32b |480b| |32b |480b| |32b |480b| |32b |480b| |32b |256b | 83eaa3b919SPawel Jakub Dawidek * |HMAC|Data| |HMAC|Data| |HMAC|Data| |HMAC|Data| |HMAC|Data| |HMAC|Data| |HMAC|Data| |HMAC|Data| |HMAC|Data | 84eaa3b919SPawel Jakub Dawidek * +----+----+ +----+----+ +----+----+ +----+----+ +----+----+ +----+----+ +----+----+ +----+----+ +----+-----+ 85eaa3b919SPawel Jakub Dawidek * |512 bytes| |512 bytes| |512 bytes| |512 bytes| |512 bytes| |512 bytes| |512 bytes| |512 bytes| |288 bytes | 86eaa3b919SPawel Jakub Dawidek * +---------+ +---------+ +---------+ +---------+ +---------+ +---------+ +---------+ +---------+ |224 unused| 87eaa3b919SPawel Jakub Dawidek * +----------+ 88eaa3b919SPawel Jakub Dawidek * da0.eli: +----+----+----+----+----+----+----+----+----+ 89eaa3b919SPawel Jakub Dawidek * |480b|480b|480b|480b|480b|480b|480b|480b|256b| 90eaa3b919SPawel Jakub Dawidek * +----+----+----+----+----+----+----+----+----+ 91eaa3b919SPawel Jakub Dawidek * | 4096 bytes | 92eaa3b919SPawel Jakub Dawidek * +--------------------------------------------+ 93eaa3b919SPawel Jakub Dawidek * 94eaa3b919SPawel Jakub Dawidek * PS. You can use any sector size with geli(8). My example is using 4kB, 95eaa3b919SPawel Jakub Dawidek * because it's most efficient. For 8kB sectors you need 2 extra sectors, 96eaa3b919SPawel Jakub Dawidek * so the cost is the same as for 4kB sectors. 97eaa3b919SPawel Jakub Dawidek */ 98eaa3b919SPawel Jakub Dawidek 99eaa3b919SPawel Jakub Dawidek /* 100eaa3b919SPawel Jakub Dawidek * Code paths: 101eaa3b919SPawel Jakub Dawidek * BIO_READ: 102eaa3b919SPawel Jakub Dawidek * g_eli_start -> g_eli_auth_read -> g_io_request -> g_eli_read_done -> g_eli_auth_run -> g_eli_auth_read_done -> g_io_deliver 103eaa3b919SPawel Jakub Dawidek * BIO_WRITE: 104eaa3b919SPawel Jakub Dawidek * g_eli_start -> g_eli_auth_run -> g_eli_auth_write_done -> g_io_request -> g_eli_write_done -> g_io_deliver 105eaa3b919SPawel Jakub Dawidek */ 106eaa3b919SPawel Jakub Dawidek 107eaa3b919SPawel Jakub Dawidek MALLOC_DECLARE(M_ELI); 108eaa3b919SPawel Jakub Dawidek 109eaa3b919SPawel Jakub Dawidek /* 110eaa3b919SPawel Jakub Dawidek * Here we generate key for HMAC. Every sector has its own HMAC key, so it is 111eaa3b919SPawel Jakub Dawidek * not possible to copy sectors. 112eaa3b919SPawel Jakub Dawidek * We cannot depend on fact, that every sector has its own IV, because different 113eaa3b919SPawel Jakub Dawidek * IV doesn't change HMAC, when we use encrypt-then-authenticate method. 114eaa3b919SPawel Jakub Dawidek */ 115eaa3b919SPawel Jakub Dawidek static void 116eaa3b919SPawel Jakub Dawidek g_eli_auth_keygen(struct g_eli_softc *sc, off_t offset, u_char *key) 117eaa3b919SPawel Jakub Dawidek { 118eaa3b919SPawel Jakub Dawidek SHA256_CTX ctx; 119eaa3b919SPawel Jakub Dawidek 120eaa3b919SPawel Jakub Dawidek /* Copy precalculated SHA256 context. */ 121eaa3b919SPawel Jakub Dawidek bcopy(&sc->sc_akeyctx, &ctx, sizeof(ctx)); 122eaa3b919SPawel Jakub Dawidek SHA256_Update(&ctx, (uint8_t *)&offset, sizeof(offset)); 123eaa3b919SPawel Jakub Dawidek SHA256_Final(key, &ctx); 124eaa3b919SPawel Jakub Dawidek } 125eaa3b919SPawel Jakub Dawidek 126eaa3b919SPawel Jakub Dawidek /* 127eaa3b919SPawel Jakub Dawidek * The function is called after we read and decrypt data. 128eaa3b919SPawel Jakub Dawidek * 129eaa3b919SPawel Jakub Dawidek * g_eli_start -> g_eli_auth_read -> g_io_request -> g_eli_read_done -> g_eli_auth_run -> G_ELI_AUTH_READ_DONE -> g_io_deliver 130eaa3b919SPawel Jakub Dawidek */ 131eaa3b919SPawel Jakub Dawidek static int 132eaa3b919SPawel Jakub Dawidek g_eli_auth_read_done(struct cryptop *crp) 133eaa3b919SPawel Jakub Dawidek { 1345ad4a7c7SPawel Jakub Dawidek struct g_eli_softc *sc; 135eaa3b919SPawel Jakub Dawidek struct bio *bp; 136eaa3b919SPawel Jakub Dawidek 137eaa3b919SPawel Jakub Dawidek if (crp->crp_etype == EAGAIN) { 138eaa3b919SPawel Jakub Dawidek if (g_eli_crypto_rerun(crp) == 0) 139eaa3b919SPawel Jakub Dawidek return (0); 140eaa3b919SPawel Jakub Dawidek } 141eaa3b919SPawel Jakub Dawidek bp = (struct bio *)crp->crp_opaque; 142eaa3b919SPawel Jakub Dawidek bp->bio_inbed++; 1431e09ff3dSPawel Jakub Dawidek sc = bp->bio_to->geom->softc; 144c0341432SJohn Baldwin if (crp->crp_etype == 0) { 145c0341432SJohn Baldwin bp->bio_completed += crp->crp_payload_length; 146c0341432SJohn Baldwin G_ELI_DEBUG(3, "Crypto READ request done (%d/%d) (add=%d completed=%jd).", 147c0341432SJohn Baldwin bp->bio_inbed, bp->bio_children, crp->crp_payload_length, (intmax_t)bp->bio_completed); 148c0341432SJohn Baldwin } else { 149c0341432SJohn Baldwin u_int nsec, decr_secsize, encr_secsize, rel_sec; 150c0341432SJohn Baldwin int *errorp; 151c0341432SJohn Baldwin 152c0341432SJohn Baldwin /* Sectorsize of decrypted provider eg. 4096. */ 153c0341432SJohn Baldwin decr_secsize = bp->bio_to->sectorsize; 154c0341432SJohn Baldwin /* The real sectorsize of encrypted provider, eg. 512. */ 155c0341432SJohn Baldwin encr_secsize = 156c0341432SJohn Baldwin LIST_FIRST(&sc->sc_geom->consumer)->provider->sectorsize; 157c0341432SJohn Baldwin /* Number of sectors from decrypted provider, eg. 2. */ 158c0341432SJohn Baldwin nsec = bp->bio_length / decr_secsize; 159c0341432SJohn Baldwin /* Number of sectors from encrypted provider, eg. 18. */ 160c0341432SJohn Baldwin nsec = (nsec * sc->sc_bytes_per_sector) / encr_secsize; 161c0341432SJohn Baldwin /* Which relative sector this request decrypted. */ 1629c0e3d3aSJohn Baldwin rel_sec = ((crp->crp_buf.cb_buf + crp->crp_payload_start) - 163c0341432SJohn Baldwin (char *)bp->bio_driver2) / encr_secsize; 164c0341432SJohn Baldwin 165c0341432SJohn Baldwin errorp = (int *)((char *)bp->bio_driver2 + encr_secsize * nsec + 166c0341432SJohn Baldwin sizeof(int) * rel_sec); 167c0341432SJohn Baldwin *errorp = crp->crp_etype; 168c0341432SJohn Baldwin G_ELI_DEBUG(1, 169c0341432SJohn Baldwin "Crypto READ request failed (%d/%d) error=%d.", 170c0341432SJohn Baldwin bp->bio_inbed, bp->bio_children, crp->crp_etype); 171c0341432SJohn Baldwin if (bp->bio_error == 0 || bp->bio_error == EINTEGRITY) 172c0341432SJohn Baldwin bp->bio_error = crp->crp_etype == EBADMSG ? 173c0341432SJohn Baldwin EINTEGRITY : crp->crp_etype; 174c0341432SJohn Baldwin } 175c0341432SJohn Baldwin if (crp->crp_cipher_key != NULL) 176c0341432SJohn Baldwin g_eli_key_drop(sc, __DECONST(void *, crp->crp_cipher_key)); 177c0341432SJohn Baldwin crypto_freereq(crp); 178eaa3b919SPawel Jakub Dawidek /* 179eaa3b919SPawel Jakub Dawidek * Do we have all sectors already? 180eaa3b919SPawel Jakub Dawidek */ 181eaa3b919SPawel Jakub Dawidek if (bp->bio_inbed < bp->bio_children) 182eaa3b919SPawel Jakub Dawidek return (0); 183c0341432SJohn Baldwin 184eaa3b919SPawel Jakub Dawidek if (bp->bio_error == 0) { 185eaa3b919SPawel Jakub Dawidek u_int i, lsec, nsec, data_secsize, decr_secsize, encr_secsize; 186c0341432SJohn Baldwin u_char *srcdata, *dstdata; 187eaa3b919SPawel Jakub Dawidek 188eaa3b919SPawel Jakub Dawidek /* Sectorsize of decrypted provider eg. 4096. */ 189eaa3b919SPawel Jakub Dawidek decr_secsize = bp->bio_to->sectorsize; 190eaa3b919SPawel Jakub Dawidek /* The real sectorsize of encrypted provider, eg. 512. */ 191eaa3b919SPawel Jakub Dawidek encr_secsize = LIST_FIRST(&sc->sc_geom->consumer)->provider->sectorsize; 192eaa3b919SPawel Jakub Dawidek /* Number of data bytes in one encrypted sector, eg. 480. */ 193eaa3b919SPawel Jakub Dawidek data_secsize = sc->sc_data_per_sector; 194eaa3b919SPawel Jakub Dawidek /* Number of sectors from decrypted provider, eg. 2. */ 195eaa3b919SPawel Jakub Dawidek nsec = bp->bio_length / decr_secsize; 196eaa3b919SPawel Jakub Dawidek /* Number of sectors from encrypted provider, eg. 18. */ 197eaa3b919SPawel Jakub Dawidek nsec = (nsec * sc->sc_bytes_per_sector) / encr_secsize; 198eaa3b919SPawel Jakub Dawidek /* Last sector number in every big sector, eg. 9. */ 199eaa3b919SPawel Jakub Dawidek lsec = sc->sc_bytes_per_sector / encr_secsize; 200eaa3b919SPawel Jakub Dawidek 201eaa3b919SPawel Jakub Dawidek srcdata = bp->bio_driver2; 202eaa3b919SPawel Jakub Dawidek dstdata = bp->bio_data; 203eaa3b919SPawel Jakub Dawidek 204eaa3b919SPawel Jakub Dawidek for (i = 1; i <= nsec; i++) { 205eaa3b919SPawel Jakub Dawidek data_secsize = sc->sc_data_per_sector; 206eaa3b919SPawel Jakub Dawidek if ((i % lsec) == 0) 207eaa3b919SPawel Jakub Dawidek data_secsize = decr_secsize % data_secsize; 208c0341432SJohn Baldwin bcopy(srcdata + sc->sc_alen, dstdata, data_secsize); 209c0341432SJohn Baldwin srcdata += encr_secsize; 210c0341432SJohn Baldwin dstdata += data_secsize; 211c0341432SJohn Baldwin } 212c0341432SJohn Baldwin } else if (bp->bio_error == EINTEGRITY) { 213c0341432SJohn Baldwin u_int i, lsec, nsec, data_secsize, decr_secsize, encr_secsize; 214c0341432SJohn Baldwin int *errorp; 215c0341432SJohn Baldwin off_t coroff, corsize, dstoff; 216c0341432SJohn Baldwin 217c0341432SJohn Baldwin /* Sectorsize of decrypted provider eg. 4096. */ 218c0341432SJohn Baldwin decr_secsize = bp->bio_to->sectorsize; 219c0341432SJohn Baldwin /* The real sectorsize of encrypted provider, eg. 512. */ 220c0341432SJohn Baldwin encr_secsize = LIST_FIRST(&sc->sc_geom->consumer)->provider->sectorsize; 221c0341432SJohn Baldwin /* Number of data bytes in one encrypted sector, eg. 480. */ 222c0341432SJohn Baldwin data_secsize = sc->sc_data_per_sector; 223c0341432SJohn Baldwin /* Number of sectors from decrypted provider, eg. 2. */ 224c0341432SJohn Baldwin nsec = bp->bio_length / decr_secsize; 225c0341432SJohn Baldwin /* Number of sectors from encrypted provider, eg. 18. */ 226c0341432SJohn Baldwin nsec = (nsec * sc->sc_bytes_per_sector) / encr_secsize; 227c0341432SJohn Baldwin /* Last sector number in every big sector, eg. 9. */ 228c0341432SJohn Baldwin lsec = sc->sc_bytes_per_sector / encr_secsize; 229c0341432SJohn Baldwin 230c0341432SJohn Baldwin errorp = (int *)((char *)bp->bio_driver2 + encr_secsize * nsec); 231c0341432SJohn Baldwin coroff = -1; 232c0341432SJohn Baldwin corsize = 0; 233c0341432SJohn Baldwin dstoff = bp->bio_offset; 234c0341432SJohn Baldwin 235c0341432SJohn Baldwin for (i = 1; i <= nsec; i++) { 236c0341432SJohn Baldwin data_secsize = sc->sc_data_per_sector; 237c0341432SJohn Baldwin if ((i % lsec) == 0) 238c0341432SJohn Baldwin data_secsize = decr_secsize % data_secsize; 239c0341432SJohn Baldwin if (errorp[i - 1] == EBADMSG) { 240eaa3b919SPawel Jakub Dawidek /* 241c0341432SJohn Baldwin * Corruption detected, remember the offset if 242eaa3b919SPawel Jakub Dawidek * this is the first corrupted sector and 243eaa3b919SPawel Jakub Dawidek * increase size. 244eaa3b919SPawel Jakub Dawidek */ 245c0341432SJohn Baldwin if (coroff == -1) 246c0341432SJohn Baldwin coroff = dstoff; 247eaa3b919SPawel Jakub Dawidek corsize += data_secsize; 248eaa3b919SPawel Jakub Dawidek } else { 249eaa3b919SPawel Jakub Dawidek /* 250c0341432SJohn Baldwin * No corruption, good. 251eaa3b919SPawel Jakub Dawidek * Report previous corruption if there was one. 252eaa3b919SPawel Jakub Dawidek */ 253eaa3b919SPawel Jakub Dawidek if (coroff != -1) { 254af23b88bSEitan Adler G_ELI_DEBUG(0, "%s: Failed to authenticate %jd " 255615a3e39SEitan Adler "bytes of data at offset %jd.", 256eaa3b919SPawel Jakub Dawidek sc->sc_name, (intmax_t)corsize, 257eaa3b919SPawel Jakub Dawidek (intmax_t)coroff); 258eaa3b919SPawel Jakub Dawidek coroff = -1; 259eaa3b919SPawel Jakub Dawidek corsize = 0; 260eaa3b919SPawel Jakub Dawidek } 261eaa3b919SPawel Jakub Dawidek } 262c0341432SJohn Baldwin dstoff += data_secsize; 263eaa3b919SPawel Jakub Dawidek } 264eaa3b919SPawel Jakub Dawidek /* Report previous corruption if there was one. */ 265eaa3b919SPawel Jakub Dawidek if (coroff != -1) { 266af23b88bSEitan Adler G_ELI_DEBUG(0, "%s: Failed to authenticate %jd " 267615a3e39SEitan Adler "bytes of data at offset %jd.", 268eaa3b919SPawel Jakub Dawidek sc->sc_name, (intmax_t)corsize, (intmax_t)coroff); 269eaa3b919SPawel Jakub Dawidek } 270eaa3b919SPawel Jakub Dawidek } 271eaa3b919SPawel Jakub Dawidek free(bp->bio_driver2, M_ELI); 272eaa3b919SPawel Jakub Dawidek bp->bio_driver2 = NULL; 273eaa3b919SPawel Jakub Dawidek if (bp->bio_error != 0) { 274c0341432SJohn Baldwin if (bp->bio_error != EINTEGRITY) { 275eaa3b919SPawel Jakub Dawidek G_ELI_LOGREQ(0, bp, 276eaa3b919SPawel Jakub Dawidek "Crypto READ request failed (error=%d).", 277eaa3b919SPawel Jakub Dawidek bp->bio_error); 278eaa3b919SPawel Jakub Dawidek } 279eaa3b919SPawel Jakub Dawidek bp->bio_completed = 0; 280eaa3b919SPawel Jakub Dawidek } 281eaa3b919SPawel Jakub Dawidek /* 282eaa3b919SPawel Jakub Dawidek * Read is finished, send it up. 283eaa3b919SPawel Jakub Dawidek */ 284eaa3b919SPawel Jakub Dawidek g_io_deliver(bp, bp->bio_error); 2855ad4a7c7SPawel Jakub Dawidek atomic_subtract_int(&sc->sc_inflight, 1); 286eaa3b919SPawel Jakub Dawidek return (0); 287eaa3b919SPawel Jakub Dawidek } 288eaa3b919SPawel Jakub Dawidek 289eaa3b919SPawel Jakub Dawidek /* 290eaa3b919SPawel Jakub Dawidek * The function is called after data encryption. 291eaa3b919SPawel Jakub Dawidek * 292eaa3b919SPawel Jakub Dawidek * g_eli_start -> g_eli_auth_run -> G_ELI_AUTH_WRITE_DONE -> g_io_request -> g_eli_write_done -> g_io_deliver 293eaa3b919SPawel Jakub Dawidek */ 294eaa3b919SPawel Jakub Dawidek static int 295eaa3b919SPawel Jakub Dawidek g_eli_auth_write_done(struct cryptop *crp) 296eaa3b919SPawel Jakub Dawidek { 297eaa3b919SPawel Jakub Dawidek struct g_eli_softc *sc; 298eaa3b919SPawel Jakub Dawidek struct g_consumer *cp; 299eaa3b919SPawel Jakub Dawidek struct bio *bp, *cbp, *cbp2; 300eaa3b919SPawel Jakub Dawidek u_int nsec; 301eaa3b919SPawel Jakub Dawidek 302eaa3b919SPawel Jakub Dawidek if (crp->crp_etype == EAGAIN) { 303eaa3b919SPawel Jakub Dawidek if (g_eli_crypto_rerun(crp) == 0) 304eaa3b919SPawel Jakub Dawidek return (0); 305eaa3b919SPawel Jakub Dawidek } 306eaa3b919SPawel Jakub Dawidek bp = (struct bio *)crp->crp_opaque; 307eaa3b919SPawel Jakub Dawidek bp->bio_inbed++; 308eaa3b919SPawel Jakub Dawidek if (crp->crp_etype == 0) { 309eaa3b919SPawel Jakub Dawidek G_ELI_DEBUG(3, "Crypto WRITE request done (%d/%d).", 310eaa3b919SPawel Jakub Dawidek bp->bio_inbed, bp->bio_children); 311eaa3b919SPawel Jakub Dawidek } else { 312eaa3b919SPawel Jakub Dawidek G_ELI_DEBUG(1, "Crypto WRITE request failed (%d/%d) error=%d.", 313eaa3b919SPawel Jakub Dawidek bp->bio_inbed, bp->bio_children, crp->crp_etype); 314eaa3b919SPawel Jakub Dawidek if (bp->bio_error == 0) 315eaa3b919SPawel Jakub Dawidek bp->bio_error = crp->crp_etype; 316eaa3b919SPawel Jakub Dawidek } 3171e09ff3dSPawel Jakub Dawidek sc = bp->bio_to->geom->softc; 318c0341432SJohn Baldwin if (crp->crp_cipher_key != NULL) 319c0341432SJohn Baldwin g_eli_key_drop(sc, __DECONST(void *, crp->crp_cipher_key)); 320c0341432SJohn Baldwin crypto_freereq(crp); 321eaa3b919SPawel Jakub Dawidek /* 322eaa3b919SPawel Jakub Dawidek * All sectors are already encrypted? 323eaa3b919SPawel Jakub Dawidek */ 324eaa3b919SPawel Jakub Dawidek if (bp->bio_inbed < bp->bio_children) 325eaa3b919SPawel Jakub Dawidek return (0); 326eaa3b919SPawel Jakub Dawidek if (bp->bio_error != 0) { 327eaa3b919SPawel Jakub Dawidek G_ELI_LOGREQ(0, bp, "Crypto WRITE request failed (error=%d).", 328eaa3b919SPawel Jakub Dawidek bp->bio_error); 329eaa3b919SPawel Jakub Dawidek free(bp->bio_driver2, M_ELI); 330eaa3b919SPawel Jakub Dawidek bp->bio_driver2 = NULL; 331eaa3b919SPawel Jakub Dawidek cbp = bp->bio_driver1; 332eaa3b919SPawel Jakub Dawidek bp->bio_driver1 = NULL; 333eaa3b919SPawel Jakub Dawidek g_destroy_bio(cbp); 334eaa3b919SPawel Jakub Dawidek g_io_deliver(bp, bp->bio_error); 3355ad4a7c7SPawel Jakub Dawidek atomic_subtract_int(&sc->sc_inflight, 1); 336eaa3b919SPawel Jakub Dawidek return (0); 337eaa3b919SPawel Jakub Dawidek } 338eaa3b919SPawel Jakub Dawidek cp = LIST_FIRST(&sc->sc_geom->consumer); 339eaa3b919SPawel Jakub Dawidek cbp = bp->bio_driver1; 340eaa3b919SPawel Jakub Dawidek bp->bio_driver1 = NULL; 341eaa3b919SPawel Jakub Dawidek cbp->bio_to = cp->provider; 342eaa3b919SPawel Jakub Dawidek cbp->bio_done = g_eli_write_done; 343eaa3b919SPawel Jakub Dawidek 344eaa3b919SPawel Jakub Dawidek /* Number of sectors from decrypted provider, eg. 1. */ 345eaa3b919SPawel Jakub Dawidek nsec = bp->bio_length / bp->bio_to->sectorsize; 346eaa3b919SPawel Jakub Dawidek /* Number of sectors from encrypted provider, eg. 9. */ 347eaa3b919SPawel Jakub Dawidek nsec = (nsec * sc->sc_bytes_per_sector) / cp->provider->sectorsize; 348eaa3b919SPawel Jakub Dawidek 349eaa3b919SPawel Jakub Dawidek cbp->bio_length = cp->provider->sectorsize * nsec; 350eaa3b919SPawel Jakub Dawidek cbp->bio_offset = (bp->bio_offset / bp->bio_to->sectorsize) * sc->sc_bytes_per_sector; 351eaa3b919SPawel Jakub Dawidek cbp->bio_data = bp->bio_driver2; 352eaa3b919SPawel Jakub Dawidek 353eaa3b919SPawel Jakub Dawidek /* 354eaa3b919SPawel Jakub Dawidek * We write more than what is requested, so we have to be ready to write 355cd853791SKonstantin Belousov * more than maxphys. 356eaa3b919SPawel Jakub Dawidek */ 357eaa3b919SPawel Jakub Dawidek cbp2 = NULL; 358cd853791SKonstantin Belousov if (cbp->bio_length > maxphys) { 359eaa3b919SPawel Jakub Dawidek cbp2 = g_duplicate_bio(bp); 360cd853791SKonstantin Belousov cbp2->bio_length = cbp->bio_length - maxphys; 361cd853791SKonstantin Belousov cbp2->bio_data = cbp->bio_data + maxphys; 362cd853791SKonstantin Belousov cbp2->bio_offset = cbp->bio_offset + maxphys; 363eaa3b919SPawel Jakub Dawidek cbp2->bio_to = cp->provider; 364eaa3b919SPawel Jakub Dawidek cbp2->bio_done = g_eli_write_done; 365cd853791SKonstantin Belousov cbp->bio_length = maxphys; 366eaa3b919SPawel Jakub Dawidek } 367eaa3b919SPawel Jakub Dawidek /* 368eaa3b919SPawel Jakub Dawidek * Send encrypted data to the provider. 369eaa3b919SPawel Jakub Dawidek */ 370eaa3b919SPawel Jakub Dawidek G_ELI_LOGREQ(2, cbp, "Sending request."); 371eaa3b919SPawel Jakub Dawidek bp->bio_inbed = 0; 372eaa3b919SPawel Jakub Dawidek bp->bio_children = (cbp2 != NULL ? 2 : 1); 373eaa3b919SPawel Jakub Dawidek g_io_request(cbp, cp); 374eaa3b919SPawel Jakub Dawidek if (cbp2 != NULL) { 375eaa3b919SPawel Jakub Dawidek G_ELI_LOGREQ(2, cbp2, "Sending request."); 376eaa3b919SPawel Jakub Dawidek g_io_request(cbp2, cp); 377eaa3b919SPawel Jakub Dawidek } 378eaa3b919SPawel Jakub Dawidek return (0); 379eaa3b919SPawel Jakub Dawidek } 380eaa3b919SPawel Jakub Dawidek 381eaa3b919SPawel Jakub Dawidek void 382eaa3b919SPawel Jakub Dawidek g_eli_auth_read(struct g_eli_softc *sc, struct bio *bp) 383eaa3b919SPawel Jakub Dawidek { 384eaa3b919SPawel Jakub Dawidek struct g_consumer *cp; 385eaa3b919SPawel Jakub Dawidek struct bio *cbp, *cbp2; 386eaa3b919SPawel Jakub Dawidek size_t size; 387eaa3b919SPawel Jakub Dawidek off_t nsec; 388eaa3b919SPawel Jakub Dawidek 389eaa3b919SPawel Jakub Dawidek bp->bio_pflags = 0; 390eaa3b919SPawel Jakub Dawidek 391eaa3b919SPawel Jakub Dawidek cp = LIST_FIRST(&sc->sc_geom->consumer); 392eaa3b919SPawel Jakub Dawidek cbp = bp->bio_driver1; 393eaa3b919SPawel Jakub Dawidek bp->bio_driver1 = NULL; 394eaa3b919SPawel Jakub Dawidek cbp->bio_to = cp->provider; 395eaa3b919SPawel Jakub Dawidek cbp->bio_done = g_eli_read_done; 396eaa3b919SPawel Jakub Dawidek 397eaa3b919SPawel Jakub Dawidek /* Number of sectors from decrypted provider, eg. 1. */ 398eaa3b919SPawel Jakub Dawidek nsec = bp->bio_length / bp->bio_to->sectorsize; 399eaa3b919SPawel Jakub Dawidek /* Number of sectors from encrypted provider, eg. 9. */ 400eaa3b919SPawel Jakub Dawidek nsec = (nsec * sc->sc_bytes_per_sector) / cp->provider->sectorsize; 401eaa3b919SPawel Jakub Dawidek 402eaa3b919SPawel Jakub Dawidek cbp->bio_length = cp->provider->sectorsize * nsec; 403eaa3b919SPawel Jakub Dawidek size = cbp->bio_length; 404c0341432SJohn Baldwin size += sizeof(int) * nsec; 405eaa3b919SPawel Jakub Dawidek size += G_ELI_AUTH_SECKEYLEN * nsec; 406eaa3b919SPawel Jakub Dawidek cbp->bio_offset = (bp->bio_offset / bp->bio_to->sectorsize) * sc->sc_bytes_per_sector; 407eaa3b919SPawel Jakub Dawidek bp->bio_driver2 = malloc(size, M_ELI, M_WAITOK); 408eaa3b919SPawel Jakub Dawidek cbp->bio_data = bp->bio_driver2; 409eaa3b919SPawel Jakub Dawidek 410c0341432SJohn Baldwin /* Clear the error array. */ 411c0341432SJohn Baldwin memset((char *)bp->bio_driver2 + cbp->bio_length, 0, 412c0341432SJohn Baldwin sizeof(int) * nsec); 413c0341432SJohn Baldwin 414eaa3b919SPawel Jakub Dawidek /* 415eaa3b919SPawel Jakub Dawidek * We read more than what is requested, so we have to be ready to read 416cd853791SKonstantin Belousov * more than maxphys. 417eaa3b919SPawel Jakub Dawidek */ 418eaa3b919SPawel Jakub Dawidek cbp2 = NULL; 419cd853791SKonstantin Belousov if (cbp->bio_length > maxphys) { 420eaa3b919SPawel Jakub Dawidek cbp2 = g_duplicate_bio(bp); 421cd853791SKonstantin Belousov cbp2->bio_length = cbp->bio_length - maxphys; 422cd853791SKonstantin Belousov cbp2->bio_data = cbp->bio_data + maxphys; 423cd853791SKonstantin Belousov cbp2->bio_offset = cbp->bio_offset + maxphys; 424eaa3b919SPawel Jakub Dawidek cbp2->bio_to = cp->provider; 425eaa3b919SPawel Jakub Dawidek cbp2->bio_done = g_eli_read_done; 426cd853791SKonstantin Belousov cbp->bio_length = maxphys; 427eaa3b919SPawel Jakub Dawidek } 428eaa3b919SPawel Jakub Dawidek /* 429eaa3b919SPawel Jakub Dawidek * Read encrypted data from provider. 430eaa3b919SPawel Jakub Dawidek */ 431eaa3b919SPawel Jakub Dawidek G_ELI_LOGREQ(2, cbp, "Sending request."); 432eaa3b919SPawel Jakub Dawidek g_io_request(cbp, cp); 433eaa3b919SPawel Jakub Dawidek if (cbp2 != NULL) { 434eaa3b919SPawel Jakub Dawidek G_ELI_LOGREQ(2, cbp2, "Sending request."); 435eaa3b919SPawel Jakub Dawidek g_io_request(cbp2, cp); 436eaa3b919SPawel Jakub Dawidek } 437eaa3b919SPawel Jakub Dawidek } 438eaa3b919SPawel Jakub Dawidek 439eaa3b919SPawel Jakub Dawidek /* 440eaa3b919SPawel Jakub Dawidek * This is the main function responsible for cryptography (ie. communication 441eaa3b919SPawel Jakub Dawidek * with crypto(9) subsystem). 442056638c4SPawel Jakub Dawidek * 443056638c4SPawel Jakub Dawidek * BIO_READ: 444056638c4SPawel Jakub Dawidek * g_eli_start -> g_eli_auth_read -> g_io_request -> g_eli_read_done -> G_ELI_AUTH_RUN -> g_eli_auth_read_done -> g_io_deliver 445056638c4SPawel Jakub Dawidek * BIO_WRITE: 446056638c4SPawel Jakub Dawidek * g_eli_start -> G_ELI_AUTH_RUN -> g_eli_auth_write_done -> g_io_request -> g_eli_write_done -> g_io_deliver 447eaa3b919SPawel Jakub Dawidek */ 448eaa3b919SPawel Jakub Dawidek void 449eaa3b919SPawel Jakub Dawidek g_eli_auth_run(struct g_eli_worker *wr, struct bio *bp) 450eaa3b919SPawel Jakub Dawidek { 451eaa3b919SPawel Jakub Dawidek struct g_eli_softc *sc; 45268f6800cSMark Johnston struct cryptopq crpq; 453eaa3b919SPawel Jakub Dawidek struct cryptop *crp; 454eaa3b919SPawel Jakub Dawidek u_int i, lsec, nsec, data_secsize, decr_secsize, encr_secsize; 455eaa3b919SPawel Jakub Dawidek off_t dstoff; 456c0341432SJohn Baldwin u_char *p, *data, *authkey, *plaindata; 4575ee9ea19SPawel Jakub Dawidek int error; 45868f6800cSMark Johnston bool batch; 459eaa3b919SPawel Jakub Dawidek 460eaa3b919SPawel Jakub Dawidek G_ELI_LOGREQ(3, bp, "%s", __func__); 461eaa3b919SPawel Jakub Dawidek 462eaa3b919SPawel Jakub Dawidek bp->bio_pflags = wr->w_number; 463eaa3b919SPawel Jakub Dawidek sc = wr->w_softc; 464eaa3b919SPawel Jakub Dawidek /* Sectorsize of decrypted provider eg. 4096. */ 465eaa3b919SPawel Jakub Dawidek decr_secsize = bp->bio_to->sectorsize; 466eaa3b919SPawel Jakub Dawidek /* The real sectorsize of encrypted provider, eg. 512. */ 467eaa3b919SPawel Jakub Dawidek encr_secsize = LIST_FIRST(&sc->sc_geom->consumer)->provider->sectorsize; 468eaa3b919SPawel Jakub Dawidek /* Number of data bytes in one encrypted sector, eg. 480. */ 469eaa3b919SPawel Jakub Dawidek data_secsize = sc->sc_data_per_sector; 470eaa3b919SPawel Jakub Dawidek /* Number of sectors from decrypted provider, eg. 2. */ 471eaa3b919SPawel Jakub Dawidek nsec = bp->bio_length / decr_secsize; 472eaa3b919SPawel Jakub Dawidek /* Number of sectors from encrypted provider, eg. 18. */ 473eaa3b919SPawel Jakub Dawidek nsec = (nsec * sc->sc_bytes_per_sector) / encr_secsize; 474eaa3b919SPawel Jakub Dawidek /* Last sector number in every big sector, eg. 9. */ 475eaa3b919SPawel Jakub Dawidek lsec = sc->sc_bytes_per_sector / encr_secsize; 476eaa3b919SPawel Jakub Dawidek /* Destination offset, used for IV generation. */ 477eaa3b919SPawel Jakub Dawidek dstoff = (bp->bio_offset / bp->bio_to->sectorsize) * sc->sc_bytes_per_sector; 478eaa3b919SPawel Jakub Dawidek 479eaa3b919SPawel Jakub Dawidek plaindata = bp->bio_data; 480eaa3b919SPawel Jakub Dawidek if (bp->bio_cmd == BIO_READ) { 481eaa3b919SPawel Jakub Dawidek data = bp->bio_driver2; 482c0341432SJohn Baldwin p = data + encr_secsize * nsec; 483c0341432SJohn Baldwin p += sizeof(int) * nsec; 484eaa3b919SPawel Jakub Dawidek } else { 485eaa3b919SPawel Jakub Dawidek size_t size; 486eaa3b919SPawel Jakub Dawidek 487eaa3b919SPawel Jakub Dawidek size = encr_secsize * nsec; 488eaa3b919SPawel Jakub Dawidek size += G_ELI_AUTH_SECKEYLEN * nsec; 489ae8b1f90SRuslan Bukin size += sizeof(uintptr_t); /* Space for alignment. */ 490eaa3b919SPawel Jakub Dawidek data = malloc(size, M_ELI, M_WAITOK); 491eaa3b919SPawel Jakub Dawidek bp->bio_driver2 = data; 492eaa3b919SPawel Jakub Dawidek p = data + encr_secsize * nsec; 493eaa3b919SPawel Jakub Dawidek } 494eaa3b919SPawel Jakub Dawidek bp->bio_inbed = 0; 495eaa3b919SPawel Jakub Dawidek bp->bio_children = nsec; 496eaa3b919SPawel Jakub Dawidek 497ae8b1f90SRuslan Bukin #if defined(__mips_n64) || defined(__mips_o64) 498ae8b1f90SRuslan Bukin p = (char *)roundup((uintptr_t)p, sizeof(uintptr_t)); 499ae8b1f90SRuslan Bukin #endif 500ae8b1f90SRuslan Bukin 50168f6800cSMark Johnston TAILQ_INIT(&crpq); 50268f6800cSMark Johnston batch = atomic_load_int(&g_eli_batch) != 0; 50368f6800cSMark Johnston 504eaa3b919SPawel Jakub Dawidek for (i = 1; i <= nsec; i++, dstoff += encr_secsize) { 505c0341432SJohn Baldwin crp = crypto_getreq(wr->w_sid, M_WAITOK); 506eaa3b919SPawel Jakub Dawidek authkey = (u_char *)p; p += G_ELI_AUTH_SECKEYLEN; 507eaa3b919SPawel Jakub Dawidek 508eaa3b919SPawel Jakub Dawidek data_secsize = sc->sc_data_per_sector; 509ea5eee64SConrad Meyer if ((i % lsec) == 0) { 510eaa3b919SPawel Jakub Dawidek data_secsize = decr_secsize % data_secsize; 511ea5eee64SConrad Meyer /* 512ea5eee64SConrad Meyer * Last encrypted sector of each decrypted sector is 513ea5eee64SConrad Meyer * only partially filled. 514ea5eee64SConrad Meyer */ 515ea5eee64SConrad Meyer if (bp->bio_cmd == BIO_WRITE) 516ea5eee64SConrad Meyer memset(data + sc->sc_alen + data_secsize, 0, 517ea5eee64SConrad Meyer encr_secsize - sc->sc_alen - data_secsize); 518*0fcafe85SMark Johnston } else if (data_secsize + sc->sc_alen != encr_secsize) { 519*0fcafe85SMark Johnston /* 520*0fcafe85SMark Johnston * If the HMAC size is not a multiple of 128 bits, the 521*0fcafe85SMark Johnston * per-sector data size is rounded down to ensure that 522*0fcafe85SMark Johnston * encryption can be performed without requiring any 523*0fcafe85SMark Johnston * padding. In this case, each sector contains unused 524*0fcafe85SMark Johnston * bytes. 525*0fcafe85SMark Johnston */ 526*0fcafe85SMark Johnston if (bp->bio_cmd == BIO_WRITE) 527*0fcafe85SMark Johnston memset(data + sc->sc_alen + data_secsize, 0, 528*0fcafe85SMark Johnston encr_secsize - sc->sc_alen - data_secsize); 529ea5eee64SConrad Meyer } 530eaa3b919SPawel Jakub Dawidek 531c0341432SJohn Baldwin if (bp->bio_cmd == BIO_WRITE) { 532eaa3b919SPawel Jakub Dawidek bcopy(plaindata, data + sc->sc_alen, data_secsize); 533eaa3b919SPawel Jakub Dawidek plaindata += data_secsize; 534eaa3b919SPawel Jakub Dawidek } 535eaa3b919SPawel Jakub Dawidek 5369c0e3d3aSJohn Baldwin crypto_use_buf(crp, data, sc->sc_alen + data_secsize); 537eaa3b919SPawel Jakub Dawidek crp->crp_opaque = (void *)bp; 53889fac384SJohn-Mark Gurney data += encr_secsize; 53908fca7a5SJohn-Mark Gurney crp->crp_flags = CRYPTO_F_CBIFSYNC; 540eaa3b919SPawel Jakub Dawidek if (bp->bio_cmd == BIO_WRITE) { 541eaa3b919SPawel Jakub Dawidek crp->crp_callback = g_eli_auth_write_done; 542c0341432SJohn Baldwin crp->crp_op = CRYPTO_OP_ENCRYPT | 543c0341432SJohn Baldwin CRYPTO_OP_COMPUTE_DIGEST; 544eaa3b919SPawel Jakub Dawidek } else { 545eaa3b919SPawel Jakub Dawidek crp->crp_callback = g_eli_auth_read_done; 546c0341432SJohn Baldwin crp->crp_op = CRYPTO_OP_DECRYPT | 547c0341432SJohn Baldwin CRYPTO_OP_VERIFY_DIGEST; 548eaa3b919SPawel Jakub Dawidek } 549eaa3b919SPawel Jakub Dawidek 550c0341432SJohn Baldwin crp->crp_digest_start = 0; 551c0341432SJohn Baldwin crp->crp_payload_start = sc->sc_alen; 552c0341432SJohn Baldwin crp->crp_payload_length = data_secsize; 553c0341432SJohn Baldwin if ((sc->sc_flags & G_ELI_FLAG_FIRST_KEY) == 0) { 554c0341432SJohn Baldwin crp->crp_cipher_key = g_eli_key_hold(sc, dstoff, 555c0341432SJohn Baldwin encr_secsize); 556c0341432SJohn Baldwin } 557aafaa8b7SAlan Somers if (g_eli_ivlen(sc->sc_ealgo) != 0) { 558aafaa8b7SAlan Somers crp->crp_flags |= CRYPTO_F_IV_SEPARATE; 559c0341432SJohn Baldwin g_eli_crypto_ivgen(sc, dstoff, crp->crp_iv, 560c0341432SJohn Baldwin sizeof(crp->crp_iv)); 561aafaa8b7SAlan Somers } 562eaa3b919SPawel Jakub Dawidek 563eaa3b919SPawel Jakub Dawidek g_eli_auth_keygen(sc, dstoff, authkey); 564c0341432SJohn Baldwin crp->crp_auth_key = authkey; 565eaa3b919SPawel Jakub Dawidek 56668f6800cSMark Johnston if (batch) { 56768f6800cSMark Johnston TAILQ_INSERT_TAIL(&crpq, crp, crp_next); 56868f6800cSMark Johnston } else { 5695ee9ea19SPawel Jakub Dawidek error = crypto_dispatch(crp); 57068f6800cSMark Johnston KASSERT(error == 0, 57168f6800cSMark Johnston ("crypto_dispatch() failed (error=%d)", error)); 572eaa3b919SPawel Jakub Dawidek } 573eaa3b919SPawel Jakub Dawidek } 57468f6800cSMark Johnston 57568f6800cSMark Johnston if (batch) 57668f6800cSMark Johnston crypto_dispatch_batch(&crpq, 0); 57768f6800cSMark Johnston } 578