static int calc_and_compare_checksum(const unsigned char *buf, size_t len, uint32_t expected) { const uint16_t *buf16 = (const uint16_t *) buf; size_t len16 = len/2; uint32_t result = fletcher32(buf16, len16); return result == expected; }
static void test_checksum_fletcher32_0to1_undetected(void) { /* fletcher cannot distinguish between all 0 and all 1 segments */ unsigned char buf0[16] = { 0xA1, 0xA1, 0xA1, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x1A, 0x1A, 0x1A, }; uint32_t expect = fletcher32((const uint16_t *) buf0, sizeof(buf0)/2); unsigned char buf1[16] = { 0xA1, 0xA1, 0xA1, 0xA1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1A, 0x1A, 0x1A, }; TEST_ASSERT(calc_and_compare_checksum(buf1, sizeof(buf1), expect)); }
uint32_t riotboot_hdr_checksum(const riotboot_hdr_t *riotboot_hdr) { return fletcher32((uint16_t *)riotboot_hdr, offsetof(riotboot_hdr_t, chksum) / sizeof(uint16_t)); }
int compress_block_generic(struct s_blockinfo *blkinfo) { char *bufcomp=NULL; int attempt=0; int compalgo; int complevel; u64 compsize; u64 bufsize; int res; bufsize = (blkinfo->blkrealsize) + (blkinfo->blkrealsize / 16) + 64 + 3; // alloc bigger buffer else lzo will crash if ((bufcomp=malloc(bufsize))==NULL) { errprintf("malloc(%ld) failed: out of memory\n", (long)bufsize); return -1; } // compression level/algo to use for the first attempt compalgo=g_options.compressalgo; complevel=g_options.compresslevel; // compress the block do { switch (compalgo) { #ifdef OPTION_LZO_SUPPORT case COMPRESS_LZO: res=compress_block_lzo(blkinfo->blkrealsize, &compsize, (u8*)blkinfo->blkdata, (void*)bufcomp, bufsize, complevel); blkinfo->blkcompalgo=COMPRESS_LZO; break; #endif // OPTION_LZO_SUPPORT case COMPRESS_GZIP: res=compress_block_gzip(blkinfo->blkrealsize, &compsize, (u8*)blkinfo->blkdata, (void*)bufcomp, bufsize, complevel); blkinfo->blkcompalgo=COMPRESS_GZIP; break; case COMPRESS_BZIP2: res=compress_block_bzip2(blkinfo->blkrealsize, &compsize, (u8*)blkinfo->blkdata, (void*)bufcomp, bufsize, complevel); blkinfo->blkcompalgo=COMPRESS_BZIP2; break; #ifdef OPTION_LZMA_SUPPORT case COMPRESS_LZMA: res=compress_block_lzma(blkinfo->blkrealsize, &compsize, (u8*)blkinfo->blkdata, (void*)bufcomp, bufsize, complevel); blkinfo->blkcompalgo=COMPRESS_LZMA; break; #endif // OPTION_LZMA_SUPPORT default: free(bufcomp); msgprintf(2, "invalid compression level: %d\n", (int)compalgo); return -1; } // retry if high compression was used and compression failed because of FSAERR_ENOMEM if ((res == FSAERR_ENOMEM) && (compalgo > FSA_DEF_COMPRESS_ALGO)) { errprintf("attempt to compress the current block using an alternative algorithm (\"-z%d\")\n", FSA_DEF_COMPRESS_ALGO); compalgo = FSA_DEF_COMPRESS_ALGO; complevel = FSA_DEF_COMPRESS_LEVEL; } } while ((res == FSAERR_ENOMEM) && (attempt++ == 0)); // check compression status and efficiency if ((res==FSAERR_SUCCESS) && (compsize < blkinfo->blkrealsize)) // compression worked and saved space { free(blkinfo->blkdata); // free old buffer (with uncompressed data) blkinfo->blkdata=bufcomp; // new buffer (with compressed data) blkinfo->blkcompsize=compsize; // size after compression and before encryption blkinfo->blkarsize=compsize; // in case there is no encryption to set this //errprintf ("COMP_DBG: block successfully compressed using %s\n", compress_algo_int_to_string(compalgo)); } else // compressed version is bigger or compression failed: keep the original block { memcpy(bufcomp, blkinfo->blkdata, blkinfo->blkrealsize); free(blkinfo->blkdata); // free old buffer blkinfo->blkdata=bufcomp; // new buffer blkinfo->blkcompsize=blkinfo->blkrealsize; // size after compression and before encryption blkinfo->blkarsize=blkinfo->blkrealsize; // in case there is no encryption to set this blkinfo->blkcompalgo=COMPRESS_NONE; //errprintf ("COMP_DBG: block copied uncompressed, attempted using %s\n", compress_algo_int_to_string(compalgo)); } u64 cryptsize; char *bufcrypt=NULL; if (g_options.encryptalgo==ENCRYPT_BLOWFISH) { if ((bufcrypt=malloc(bufsize+8))==NULL) { errprintf("malloc(%ld) failed: out of memory\n", (long)bufsize+8); return -1; } if ((res=crypto_blowfish(blkinfo->blkcompsize, &cryptsize, (u8*)bufcomp, (u8*)bufcrypt, g_options.encryptpass, strlen((char*)g_options.encryptpass), 1))!=0) { errprintf("crypt_block_blowfish() failed\n"); return -1; } free(bufcomp); blkinfo->blkdata=bufcrypt; blkinfo->blkarsize=cryptsize; blkinfo->blkcryptalgo=ENCRYPT_BLOWFISH; } else { blkinfo->blkcryptalgo=ENCRYPT_NONE; } // calculates the final block checksum (block as it will be stored in the archive) blkinfo->blkarcsum=fletcher32((void*)blkinfo->blkdata, blkinfo->blkarsize); return 0; }
int decompress_block_generic(struct s_blockinfo *blkinfo) { u64 checkorigsize; char *bufcomp=NULL; int res; // allocate memory for uncompressed data if ((bufcomp=malloc(blkinfo->blkrealsize))==NULL) { errprintf("malloc(%ld) failed: cannot allocate memory for compressed block\n", (long)blkinfo->blkrealsize); return -1; } // check the block checksum if (fletcher32((u8*)blkinfo->blkdata, blkinfo->blkarsize)!=(blkinfo->blkarcsum)) { errprintf("block is corrupt at blockoffset=%ld, blksize=%ld\n", (long)blkinfo->blkoffset, (long)blkinfo->blkrealsize); memset(bufcomp, 0, blkinfo->blkrealsize); } else // data not corrupted, decompresses the block { if ((blkinfo->blkcryptalgo!=ENCRYPT_NONE) && (g_options.encryptalgo!=ENCRYPT_BLOWFISH)) { msgprintf(MSG_DEBUG1, "this archive has been encrypted, you have to provide a password " "on the command line using option '-c'\n"); return -1; } char *bufcrypt=NULL; u64 clearsize; if (blkinfo->blkcryptalgo==ENCRYPT_BLOWFISH) { if ((bufcrypt=malloc(blkinfo->blkrealsize+8))==NULL) { errprintf("malloc(%ld) failed: out of memory\n", (long)blkinfo->blkrealsize+8); return -1; } if ((res=crypto_blowfish(blkinfo->blkarsize, &clearsize, (u8*)blkinfo->blkdata, (u8*)bufcrypt, g_options.encryptpass, strlen((char*)g_options.encryptpass), 0))!=0) { errprintf("crypt_block_blowfish() failed\n"); return -1; } if (clearsize!=blkinfo->blkcompsize) { errprintf("clearsize does not match blkcompsize: clearsize=%ld and blkcompsize=%ld\n", (long)clearsize, (long)blkinfo->blkcompsize); return -1; } free(blkinfo->blkdata); blkinfo->blkdata=bufcrypt; } switch (blkinfo->blkcompalgo) { case COMPRESS_NONE: memcpy(bufcomp, blkinfo->blkdata, blkinfo->blkarsize); res=0; break; #ifdef OPTION_LZO_SUPPORT case COMPRESS_LZO: if ((res=uncompress_block_lzo(blkinfo->blkcompsize, &checkorigsize, (void*)bufcomp, blkinfo->blkrealsize, (u8*)blkinfo->blkdata))!=0) { errprintf("uncompress_block_lzo()=%d failed: finalsize=%ld and checkorigsize=%ld\n", res, (long)blkinfo->blkarsize, (long)checkorigsize); memset(bufcomp, 0, blkinfo->blkrealsize); // TODO: inc(error_counter); } break; #endif // OPTION_LZO_SUPPORT case COMPRESS_GZIP: if ((res=uncompress_block_gzip(blkinfo->blkcompsize, &checkorigsize, (void*)bufcomp, blkinfo->blkrealsize, (u8*)blkinfo->blkdata))!=0) { errprintf("uncompress_block_gzip()=%d failed: finalsize=%ld and checkorigsize=%ld\n", res, (long)blkinfo->blkarsize, (long)checkorigsize); memset(bufcomp, 0, blkinfo->blkrealsize); // TODO: inc(error_counter); } break; case COMPRESS_BZIP2: if ((res=uncompress_block_bzip2(blkinfo->blkcompsize, &checkorigsize, (void*)bufcomp, blkinfo->blkrealsize, (u8*)blkinfo->blkdata))!=0) { errprintf("uncompress_block_bzip2()=%d failed: finalsize=%ld and checkorigsize=%ld\n", res, (long)blkinfo->blkarsize, (long)checkorigsize); memset(bufcomp, 0, blkinfo->blkrealsize); // TODO: inc(error_counter); } break; #ifdef OPTION_LZMA_SUPPORT case COMPRESS_LZMA: if ((res=uncompress_block_lzma(blkinfo->blkcompsize, &checkorigsize, (void*)bufcomp, blkinfo->blkrealsize, (u8*)blkinfo->blkdata))!=0) { errprintf("uncompress_block_lzma()=%d failed: finalsize=%ld and checkorigsize=%ld\n", res, (long)blkinfo->blkarsize, (long)checkorigsize); memset(bufcomp, 0, blkinfo->blkrealsize); // TODO: inc(error_counter); } break; #endif // OPTION_LZMA_SUPPORT default: errprintf("unsupported compression algorithm: %ld\n", (long)blkinfo->blkcompalgo); return -1; } free(blkinfo->blkdata); // free old buffer (with compressed data) blkinfo->blkdata=bufcomp; // pointer to new buffer with uncompressed data } return 0; }
int archreader_read_block(carchreader *ai, cdico *in_blkdico, int in_skipblock, int *out_sumok, struct s_blockinfo *out_blkinfo) { u32 arblockcsumorig; u32 arblockcsumcalc; u32 curblocksize; // data size u64 blockoffset; // offset of the block in the file u16 compalgo; // compression algo used u16 cryptalgo; // encryption algo used u32 finalsize; // compressed block size u32 compsize; u8 *buffer; bool corrupt; assert(ai); assert(out_sumok); assert(in_blkdico); assert(out_blkinfo); // init memset(out_blkinfo, 0, sizeof(struct s_blockinfo)); *out_sumok=-1; if (dico_get_u64(in_blkdico, 0, BLOCKHEADITEMKEY_BLOCKOFFSET, &blockoffset)!=0) { msgprintf(3, "cannot get blockoffset from block-header\n"); return -1; } if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_REALSIZE, &curblocksize)!=0 || curblocksize>FSA_MAX_BLKSIZE) { msgprintf(3, "cannot get blocksize from block-header\n"); return -1; } if (dico_get_u16(in_blkdico, 0, BLOCKHEADITEMKEY_COMPRESSALGO, &compalgo)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_COMPRESSALGO from block-header\n"); return -1; } if (dico_get_u16(in_blkdico, 0, BLOCKHEADITEMKEY_ENCRYPTALGO, &cryptalgo)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_ENCRYPTALGO from block-header\n"); return -1; } if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_ARSIZE, &finalsize)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_ARSIZE from block-header\n"); return -1; } if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_COMPSIZE, &compsize)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_COMPSIZE from block-header\n"); return -1; } if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_ARCSUM, &arblockcsumorig)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_ARCSUM from block-header\n"); return -1; } if (in_skipblock==true) // the main thread does not need that block (block belongs to a filesys we want to skip) { if (lseek64(ai->archfd, (long)finalsize, SEEK_CUR)<0) { sysprintf("cannot skip block (finalsize=%ld) failed\n", (long)finalsize); return -1; } return 0; } // ---- allocate memory if ((buffer=malloc(finalsize))==NULL) { errprintf("cannot allocate block: malloc(%d) failed\n", finalsize); return FSAERR_ENOMEM; } if (read(ai->archfd, buffer, (long)finalsize)!=(long)finalsize) { sysprintf("cannot read block (finalsize=%ld) failed\n", (long)finalsize); free(buffer); return -1; } // prepare blkinfo out_blkinfo->blkdata=(char*)buffer; out_blkinfo->blkrealsize=curblocksize; out_blkinfo->blkoffset=blockoffset; out_blkinfo->blkarcsum=arblockcsumorig; out_blkinfo->blkcompalgo=compalgo; out_blkinfo->blkcryptalgo=cryptalgo; out_blkinfo->blkarsize=finalsize; out_blkinfo->blkcompsize=compsize; // ---- checksum arblockcsumcalc=fletcher32(buffer, finalsize); corrupt=false; if (arblockcsumcalc!=arblockcsumorig) // bad checksum { errprintf("block is corrupt at offset=%ld, blksize=%ld\n", (long)blockoffset, (long)curblocksize); corrupt=!g_options.keepcorrupt; } if (corrupt) { free(out_blkinfo->blkdata); if ((out_blkinfo->blkdata=malloc(curblocksize))==NULL) { errprintf("cannot allocate block: malloc(%d) failed\n", curblocksize); return FSAERR_ENOMEM; } memset(out_blkinfo->blkdata, 0, curblocksize); *out_sumok=false; // go to the beginning of the corrupted contents so that the next header is searched here if (lseek64(ai->archfd, -(long long)finalsize, SEEK_CUR)<0) { errprintf("lseek64() failed\n"); } } else // no corruption detected { *out_sumok=true; } return 0; }
int archreader_read_dico(carchreader *ai, cdico *d) { u16 size; u32 headerlen; u32 origsum; u32 newsum; u8 *buffer; u8 *bufpos; u16 temp16; u32 temp32; u8 section; u16 count; u8 type; u16 key; int i; assert(ai); assert(d); // header-len, header-data, header-checksum switch (ai->filefmtver) { case 1: if (archreader_read_data(ai, &temp16, sizeof(temp16))!=0) { errprintf("imgdisk_read_data() failed\n"); return OLDERR_FATAL; } headerlen=le16_to_cpu(temp16); break; case 2: if (archreader_read_data(ai, &temp32, sizeof(temp32))!=0) { errprintf("imgdisk_read_data() failed\n"); return OLDERR_FATAL; } headerlen=le32_to_cpu(temp32); break; default: errprintf("Fatal error: invalid file format version: ai->filefmtver=%d\n", ai->filefmtver); return OLDERR_FATAL; } bufpos=buffer=malloc(headerlen); if (!buffer) { errprintf("cannot allocate memory for header\n"); return FSAERR_ENOMEM; } if (archreader_read_data(ai, buffer, headerlen)!=0) { errprintf("cannot read header data\n"); free(buffer); return OLDERR_FATAL; } if (archreader_read_data(ai, &temp32, sizeof(temp32))!=0) { errprintf("cannot read header checksum\n"); free(buffer); return OLDERR_FATAL; } origsum=le32_to_cpu(temp32); // check header-data integrity using checksum newsum=fletcher32(buffer, headerlen); if (newsum!=origsum) { errprintf("bad checksum for header\n"); free(buffer); return OLDERR_MINOR; // header corrupt --> skip file } // read count from buffer memcpy(&temp16, bufpos, sizeof(temp16)); bufpos+=sizeof(temp16); count=le16_to_cpu(temp16); // read items for (i=0; i < count; i++) { // a. read type from buffer memcpy(&type, bufpos, sizeof(type)); bufpos+=sizeof(section); // b. read section from buffer memcpy(§ion, bufpos, sizeof(section)); bufpos+=sizeof(section); // c. read key from buffer memcpy(&temp16, bufpos, sizeof(temp16)); bufpos+=sizeof(temp16); key=le16_to_cpu(temp16); // d. read sizeof(data) memcpy(&temp16, bufpos, sizeof(temp16)); bufpos+=sizeof(temp16); size=le16_to_cpu(temp16); // e. add item to dico if (dico_add_generic(d, section, key, bufpos, size, type)!=0) return OLDERR_FATAL; bufpos+=size; } free(buffer); return FSAERR_SUCCESS; }