Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  bl.c

  Sprache: C
 

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed 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 <variant/variant.h>

#include <bl.h>

#include <plat/cmsis.h>
#include <plat/gpio.h>

#include <nanohub/sha2.h>
#include <nanohub/aes.h>
#include <nanohub/rsa.h>
#include <nanohub/nanohub.h>

#include <printf.h>
#include <string.h>

static uint32_t blVerifyOsImage(const uint8_t *addr, struct OsUpdateHdr **start, uint32_t *size);


//for comms protocol
#define BL_SYNC_IN                      0x5A
#define BL_ACK                          0x79
#define BL_NAK                          0x1F
#define BL_SYNC_OUT                     0xA5

#define BL_CMD_GET                      0x00
#define BL_CMD_READ_MEM                 0x11
#define BL_CMD_WRITE_MEM                0x31
#define BL_CMD_ERASE                    0x44
#define BL_CMD_GET_SIZES                0xEE /* our own command. reports: {u32 osSz, u32 sharedSz, u32 eeSz} all in big endian */
#define BL_CMD_UPDATE_FINISHED          0xEF /* our own command. attempts to verify the update -> ACK/NAK. MUST be called after upload to mark it as completed */

#define BL_ERROR                        0xDEADBEAF /* returned in place of command in case of exchange errors */


#define BL_SHARED_AREA_FAKE_ERASE_BLK   0xFFF0
#define BL_SHARED_AREA_FAKE_ADDR        0x50000000


//linker provides these
extern uint32_t __pubkeys_start[];
extern uint32_t __pubkeys_end[];
extern uint8_t __eedata_start[];
extern uint8_t __eedata_end[];
extern uint8_t __code_start[];
extern uint8_t __code_end[];
extern uint8_t __shared_start[];
extern uint8_t __shared_end[];

enum BlFlashType
{
    BL_FLASH_BL,
    BL_FLASH_EEDATA,
    BL_FLASH_KERNEL,
    BL_FLASH_SHARED
};

static const struct blFlashTable   // For erase code, we need to know which page a given memory address is in
{
    uint8_t *address;
    uint32_t length;
    uint32_t type;
} mBlFlashTable[] =
#ifndef BL_FLASH_TABLE
{
    { (uint8_t *)(&BL),                      0x04000, BL_FLASH_BL     },
    { (uint8_t *)(__eedata_start),           0x04000, BL_FLASH_EEDATA },
    { (uint8_t *)(__eedata_start + 0x04000), 0x04000, BL_FLASH_EEDATA },
    { (uint8_t *)(__code_start),             0x04000, BL_FLASH_KERNEL },
    { (uint8_t *)(__code_start + 0x04000),   0x10000, BL_FLASH_KERNEL },
    { (uint8_t *)(__code_start + 0x14000),   0x20000, BL_FLASH_KERNEL },
    { (uint8_t *)(__shared_start),           0x20000, BL_FLASH_SHARED },
    { (uint8_t *)(__shared_start + 0x20000), 0x20000, BL_FLASH_SHARED },
};
#else
BL_FLASH_TABLE;
#endif

static const char mOsUpdateMagic[] = OS_UPDT_MAGIC;

#ifdef DEBUG_UART_PIN

static bool blLogPutcharF(void *userData, char ch)
{
    if (ch == '\n')
        gpioBitbangedUartOut('\r');

    gpioBitbangedUartOut(ch);

    return true;
}

void blLog(const char *str, ...)
{
    va_list vl;

    va_start(vl, str);
    cvprintf(blLogPutcharF, 0, NULL, str, vl);
    va_end(vl);
}

#else

#define blLog(...)

#endif

static uint32_t blExtApiGetVersion(void)
{
    return BL_VERSION_CUR;
}

static bool blProgramFlash(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2)
{
    const uint32_t sector_cnt = sizeof(mBlFlashTable) / sizeof(struct blFlashTable);
    uint32_t offset, i, j = 0;
    uint8_t *ptr;

    if (((length == 0)) ||
        ((0xFFFFFFFF - (uint32_t)dst) < (length - 1)) ||
        ((dst < mBlFlashTable[0].address)) ||
        ((dst + length) > (mBlFlashTable[sector_cnt-1].address +
                           mBlFlashTable[sector_cnt-1].length))) {
        return false;
    }

    // compute which flash block we are starting from
    for (i = 0; i < sector_cnt; i++) {
        if (dst >= mBlFlashTable[i].address &&
            dst < (mBlFlashTable[i].address + mBlFlashTable[i].length)) {
            break;
        }
    }

    // now loop through all the flash blocks and see if we have to do any
    // 0 -> 1 transitions of a bit. If so, return false
    // 1 -> 0 transitions of a bit do not require an erase
    offset = (uint32_t)(dst - mBlFlashTable[i].address);
    ptr = mBlFlashTable[i].address;
    while (j < length && i < sector_cnt) {
        if (offset == mBlFlashTable[i].length) {
            i++;
            offset = 0;
            ptr = mBlFlashTable[i].address;
        }

        if ((ptr[offset] & src[j]) != src[j]) {
            return false;
        } else {
            j++;
            offset++;
        }
    }

    if (!blPlatProgramFlash(dst, src, length, key1, key2))
        return false;

    return !memcmp(dst, src, length);
}

static void blExtApiGetSnum(uint32_t *snum, uint32_t length)
{
    blGetSnum(snum, length);
}

static bool blProgramTypedArea(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t type, uint32_t key1, uint32_t key2)
{
    const uint32_t sector_cnt = sizeof(mBlFlashTable) / sizeof(struct blFlashTable);
    uint32_t i;

    for (i = 0; i < sector_cnt; i++) {

        if ((dst >= mBlFlashTable[i].address &&
             dst < (mBlFlashTable[i].address + mBlFlashTable[i].length)) ||
            (dst < mBlFlashTable[i].address &&
             (dst + length > mBlFlashTable[i].address))) {
            if (mBlFlashTable[i].type != type)
                return false;
        }
    }

    return blProgramFlash(dst, src, length, key1, key2);
}

static bool blExtApiProgramSharedArea(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2)
{
    return blProgramTypedArea(dst, src, length, BL_FLASH_SHARED, key1, key2);
}

static bool blExtApiProgramEe(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2)
{
    return blProgramTypedArea(dst, src, length, BL_FLASH_EEDATA, key1, key2);
}

static bool blEraseTypedArea(uint32_t type, uint32_t key1, uint32_t key2)
{
    const uint32_t sector_cnt = sizeof(mBlFlashTable) / sizeof(struct blFlashTable);
    uint32_t i, erase_cnt = 0;
    uint8_t erase_mask[sector_cnt];

    for (i = 0; i < sector_cnt; i++) {
        if (mBlFlashTable[i].type == type) {
            erase_mask[i] = 1;
            erase_cnt++;
        } else {
            erase_mask[i] = 0;
        }
    }

    if (erase_cnt)
        blEraseSectors(sector_cnt, erase_mask, key1, key2);

    return true//we assume erase worked
}

static bool blExtApiEraseSharedArea(uint32_t key1, uint32_t key2)
{
    return blEraseTypedArea(BL_FLASH_SHARED, key1, key2);
}

static uint32_t blVerifyOsUpdate(struct OsUpdateHdr **start, uint32_t *size)
{
    uint32_t ret;
    int i;

    for (i = 0; i < BL_SCAN_OFFSET; i += 4) {
        ret = blVerifyOsImage(__shared_start + i, start, size);
        if (ret != OS_UPDT_HDR_CHECK_FAILED)
            break;
    }

    return ret;
}

static uint32_t blExtApiVerifyOsUpdate(void)
{
    return blVerifyOsUpdate(NULL, NULL);
}

static void blExtApiReboot(void)
{
    blReboot();
}

static const uint32_t *blExtApiGetRsaKeyInfo(uint32_t *numKeys)
{
    uint32_t numWords = __pubkeys_end - __pubkeys_start;

    if (numWords % RSA_WORDS) // something is wrong
        return NULL;

    *numKeys = numWords / RSA_WORDS;
    return __pubkeys_start;
}

static const uint32_t* blExtApiSigPaddingVerify(const uint32_t *rsaResult)
{
    uint32_t i;

    //all but first and last word of padding MUST have no zero bytes
    for (i = SHA2_HASH_WORDS + 1; i < RSA_WORDS - 1; i++) {
        if (!(uint8_t)(rsaResult[i] >>  0))
            return NULL;
        if (!(uint8_t)(rsaResult[i] >>  8))
            return NULL;
        if (!(uint8_t)(rsaResult[i] >> 16))
            return NULL;
        if (!(uint8_t)(rsaResult[i] >> 24))
            return NULL;
    }

    //first padding word must have all nonzero bytes except low byte
    if ((rsaResult[SHA2_HASH_WORDS] & 0xff) || !(rsaResult[SHA2_HASH_WORDS] & 0xff00) || !(rsaResult[SHA2_HASH_WORDS] & 0xff0000) || !(rsaResult[SHA2_HASH_WORDS] & 0xff000000))
        return NULL;

    //last padding word must have 0x0002 in top 16 bits and nonzero random bytes in lower bytes
    if ((rsaResult[RSA_WORDS - 1] >> 16) != 2)
        return NULL;
    if (!(rsaResult[RSA_WORDS - 1] & 0xff00) || !(rsaResult[RSA_WORDS - 1] & 0xff))
        return NULL;

    return rsaResult;
}

static void blApplyVerifiedUpdate(const struct OsUpdateHdr *os) //only called if an update has been found to exist and be valid, signed, etc!
{
    //copy shared to code, and if successful, erase shared area
    if (blEraseTypedArea(BL_FLASH_KERNEL, BL_FLASH_KEY1, BL_FLASH_KEY2))
        if (blProgramTypedArea(__code_start, (const uint8_t*)(os + 1), os->size, BL_FLASH_KERNEL, BL_FLASH_KEY1, BL_FLASH_KEY2))
            (void)blExtApiEraseSharedArea(BL_FLASH_KEY1, BL_FLASH_KEY2);
}

static void blWriteMark(struct OsUpdateHdr *hdr, uint32_t mark)
{
    uint8_t dstVal = mark;

    (void)blExtApiProgramSharedArea(&hdr->marker, &dstVal, sizeof(hdr->marker), BL_FLASH_KEY1, BL_FLASH_KEY2);
}

static void blUpdateMark(uint32_t old, uint32_t new)
{
    struct OsUpdateHdr *hdr = (struct OsUpdateHdr *)__shared_start;

    if (hdr->marker != old)
        return;

    blWriteMark(hdr, new);
}

static uint32_t blVerifyOsImage(const uint8_t *addr, struct OsUpdateHdr **start, uint32_t *size)
{
    const uint32_t *rsaKey, *osSigHash, *osSigPubkey, *ourHash, *rsaResult, *expectedHash = NULL;
    struct OsUpdateHdr *hdr = (struct OsUpdateHdr*)addr;
    struct OsUpdateHdr cpy;
    uint32_t i, numRsaKeys = 0, rsaStateVar1, rsaStateVar2, rsaStep = 0;
    const uint8_t *updateBinaryData;
    bool isValid = false;
    struct Sha2state sha;
    struct RsaState rsa;
    uint32_t ret = OS_UPDT_HDR_CHECK_FAILED;
    const uint32_t overhead = sizeof(*hdr) + 2 * RSA_WORDS;

    // header does not fit or is not aligned
    if (addr < __shared_start || addr > (__shared_end - overhead) || ((uintptr_t)addr & 3))
        return OS_UPDT_HDR_CHECK_FAILED;

    // image does not fit
    if (hdr->size > (__shared_end - addr - overhead))
        return OS_UPDT_HDR_CHECK_FAILED;

    // OS magic does not match
    if (memcmp(hdr->magic, mOsUpdateMagic, sizeof(hdr->magic)) != 0)
        return OS_UPDT_HDR_CHECK_FAILED;

    // we don't allow shortcuts on success path, but we want to fail quickly
    if (hdr->marker == OS_UPDT_MARKER_INVALID)
        return OS_UPDT_HDR_MARKER_INVALID;

    // download did not finish
    if (hdr->marker == OS_UPDT_MARKER_INPROGRESS)
        return OS_UPDT_HDR_MARKER_INVALID;

    //get pointers
    updateBinaryData = (const uint8_t*)(hdr + 1);
    osSigHash = (const uint32_t*)(updateBinaryData + hdr->size);
    osSigPubkey = osSigHash + RSA_WORDS;

    //make sure the pub key is known
    for (i = 0, rsaKey = blExtApiGetRsaKeyInfo(&numRsaKeys); i < numRsaKeys; i++, rsaKey += RSA_WORDS) {
        if (memcmp(rsaKey, osSigPubkey, RSA_BYTES) == 0)
            break;
    }

    if (i == numRsaKeys) {
        ret = OS_UPDT_UNKNOWN_PUBKEY;
        //signed with an unknown key -> fail
        goto fail;
    }

    //decode sig using pubkey
    do {
        rsaResult = rsaPubOpIterative(&rsa, osSigHash, osSigPubkey, &rsaStateVar1, &rsaStateVar2, &rsaStep);
    } while (rsaStep);

    if (!rsaResult) {
        //decode fails -> invalid sig
        ret = OS_UPDT_INVALID_SIGNATURE;
        goto fail;
    }

    //verify padding
    expectedHash = blExtApiSigPaddingVerify(rsaResult);

    if (!expectedHash) {
        //padding check fails -> invalid sig
        ret = OS_UPDT_INVALID_SIGNATURE_HASH;
        goto fail;
    }

    //hash the update
    sha2init(&sha);

    memcpy(&cpy, hdr, sizeof(cpy));
    cpy.marker = OS_UPDT_MARKER_INPROGRESS;
    sha2processBytes(&sha, &cpy, sizeof(cpy));
    sha2processBytes(&sha, (uint8_t*)(hdr + 1), hdr->size);
    ourHash = sha2finish(&sha);

    //verify hash match
    if (memcmp(expectedHash, ourHash, SHA2_HASH_SIZE) != 0) {
        //hash does not match -> data tampered with
        ret = OS_UPDT_INVALID_SIGNATURE_HASH; // same error; do not disclose nature of hash problem
        goto fail;
    }

    //it is valid
    isValid = true;
    ret = OS_UPDT_SUCCESS;
    if (start)
        *start = hdr;
    if (size)
        *size = hdr->size;

fail:
    //mark it appropriately
    blWriteMark(hdr, isValid ? OS_UPDT_MARKER_VERIFIED : OS_UPDT_MARKER_INVALID);
    return ret;
}

static inline bool blUpdateVerify()
{
    return blVerifyOsImage(__shared_start, NULL, NULL) == OS_UPDT_SUCCESS;
}

static uint8_t blLoaderRxByte()
{
    return blSpiTxRxByte(0);
}

static void blLoaderTxByte(uint32_t val)
{
    blSpiTxRxByte(val);
}

static void blLoaderTxBytes(const void *data, uint32_t len)
{
    const uint8_t *buf = (const uint8_t*)data;

    blLoaderTxByte(len - 1);
    while (len--)
        blLoaderTxByte(*buf++);
}

static bool blLoaderSendSyncOut()
{
    return blSpiTxRxByte(BL_SYNC_OUT) == BL_SYNC_IN;
}

static bool blLoaderSendAck(bool ack)
{
    blLoaderRxByte();
    blLoaderTxByte(ack ? BL_ACK : BL_NAK);
    return blLoaderRxByte() == BL_ACK;
}

static uint32_t blLoaderRxCmd()
{
    uint8_t cmd = blLoaderRxByte();
    uint8_t cmdNot = blSpiTxRxByte(BL_ACK);
    return (cmd ^ cmdNot) == 0xFF ? cmd : BL_ERROR;
}

static void blLoader(bool force)
{
    bool seenErase = false;
    uint32_t nextAddr = 0;
    uint32_t expectedSize = 0;

    blSetup();

    //if int pin is not low, do not bother any further
    if (blHostActive() || force) {

        blConfigIo();

        //if we saw a sync, do the bootloader thing
        if (blSyncWait(BL_SYNC_IN)) {
            static const uint8_t supportedCmds[] = {BL_CMD_GET, BL_CMD_READ_MEM, BL_CMD_WRITE_MEM, BL_CMD_ERASE, BL_CMD_GET_SIZES, BL_CMD_UPDATE_FINISHED};
            uint32_t allSizes[] = {__builtin_bswap32(__code_end - __code_start), __builtin_bswap32(__shared_end - __shared_start), __builtin_bswap32(__eedata_end - __eedata_start)};
            bool ack = true;  //we ack the sync

            ack = blLoaderSendSyncOut();

            //loop forever listening to commands
            while (1) {
                uint32_t sync, cmd, addr = 0, len, checksum = 0, i;
                uint8_t data[256];

                //send ack or NAK for last thing
                if (!blLoaderSendAck(ack))
                    goto out;

                while ((sync = blLoaderRxByte()) != BL_SYNC_IN);
                cmd = blLoaderRxCmd();

                ack = false;
                if (sync == BL_SYNC_IN && cmd != BL_ERROR)
                switch (cmd) {
                case BL_CMD_GET:

                    //ACK the command
                    (void)blLoaderSendAck(true);

                    blLoaderTxBytes(supportedCmds, sizeof(supportedCmds));
                    ack = true;
                    break;

                case BL_CMD_READ_MEM:
                    if (!seenErase)  //no reading till we erase the shared area (this way we do not leak encrypted apps' plaintexts)
                        break;

                    //ACK the command
                    (void)blLoaderSendAck(true);

                    //get address
                    for (i = 0; i < 4; i++) {
                        uint32_t byte = blLoaderRxByte();
                        checksum ^= byte;
                        addr = (addr << 8) + byte;
                    }

                    //reject addresses outside of our fake area or on invalid checksum
                    if (blLoaderRxByte() != checksum || addr < BL_SHARED_AREA_FAKE_ADDR || addr - BL_SHARED_AREA_FAKE_ADDR > __shared_end - __shared_start)
                       break;

                    //ack the address
                    (void)blLoaderSendAck(true);

                    //get the length
                    len = blLoaderRxByte();

                    //reject invalid checksum
                    if (blLoaderRxByte() != (uint8_t)~len || addr + len - BL_SHARED_AREA_FAKE_ADDR > __shared_end - __shared_start)
                       break;

                    len++;

                    //reject reads past the end of the shared area
                    if (addr + len - BL_SHARED_AREA_FAKE_ADDR > __shared_end - __shared_start)
                       break;

                    //ack the length
                    (void)blLoaderSendAck(true);

                    //read the data & send it
                    blLoaderTxBytes(__shared_start + addr - BL_SHARED_AREA_FAKE_ADDR, len);
                    ack = true;
                    break;

                case BL_CMD_WRITE_MEM:
                    if (!seenErase)  //no writing till we erase the shared area (this way we do not purposefully modify encrypted apps' plaintexts in a nefarious fashion)
                        break;

                    //ACK the command
                    (void)blLoaderSendAck(true);

                    //get address
                    for (i = 0; i < 4; i++) {
                        uint32_t byte = blLoaderRxByte();
                        checksum ^= byte;
                        addr = (addr << 8) + byte;
                    }

                    //reject addresses outside of our fake area or on invalid checksum
                    if (blLoaderRxByte() != checksum ||
                        addr < BL_SHARED_AREA_FAKE_ADDR ||
                        addr - BL_SHARED_AREA_FAKE_ADDR > __shared_end - __shared_start)
                        break;

                    addr -= BL_SHARED_AREA_FAKE_ADDR;
                    if (addr != nextAddr)
                        break;

                    //ack the address
                    (void)blLoaderSendAck(true);

                    //get the length
                    checksum = len = blLoaderRxByte();
                    len++;

                    //get bytes
                    for (i = 0; i < len; i++) {
                        uint32_t byte = blLoaderRxByte();
                        checksum ^= byte;
                        data[i] = byte;
                    }

                    //reject writes that takes out outside fo shared area or invalid checksums
                    if (blLoaderRxByte() != checksum || addr + len > __shared_end - __shared_start)
                       break;

                    // OBSOLETE: superseded by sequential contiguous write requirement
                    //if (addr && addr < sizeof(struct OsUpdateHdr))
                    //    break;

                    //a write starting at zero must be big enough to contain a full OS update header
                    if (!addr) {
                        const struct OsUpdateHdr *hdr = (const struct OsUpdateHdr*)data;

                        //verify it is at least as big as the header
                        if (len < sizeof(struct OsUpdateHdr))
                            break;

                        //check for magic
                        for (i = 0; i < sizeof(hdr->magic) && hdr->magic[i] == mOsUpdateMagic[i]; i++);

                        //verify magic check passed & marker is properly set to inprogress
                        if (i != sizeof(hdr->magic) || hdr->marker != OS_UPDT_MARKER_INPROGRESS)
                            break;
                        expectedSize = sizeof(*hdr) + hdr->size + 2 * RSA_BYTES;
                    }
                    if (addr + len > expectedSize)
                        break;

                    //do it
                    ack = blExtApiProgramSharedArea(__shared_start + addr, data, len, BL_FLASH_KEY1, BL_FLASH_KEY2);
                    blResetRxData();
                    nextAddr += len;
                    break;

                case BL_CMD_ERASE:

                    //ACK the command
                    (void)blLoaderSendAck(true);

                    //get address
                    for (i = 0; i < 2; i++) {
                        uint32_t byte = blLoaderRxByte();
                        checksum ^= byte;
                        addr = (addr << 8) + byte;
                    }

                    //reject addresses that are not our magic address or on invalid checksum
                    if (blLoaderRxByte() != checksum || addr != BL_SHARED_AREA_FAKE_ERASE_BLK)
                        break;

                    //do it
                    ack = blExtApiEraseSharedArea(BL_FLASH_KEY1, BL_FLASH_KEY2);
                    if (ack) {
                        seenErase = true;
                        nextAddr = 0;
                        expectedSize = 0;
                    }
                    blResetRxData();
                    break;

                case BL_CMD_GET_SIZES:

                    //ACK the command
                    (void)blLoaderSendAck(true);

                    blLoaderTxBytes(allSizes, sizeof(allSizes));
                    break;

                case BL_CMD_UPDATE_FINISHED:
                    blUpdateMark(OS_UPDT_MARKER_INPROGRESS, OS_UPDT_MARKER_DOWNLOADED);
                    ack = blUpdateVerify();
                    break;
                }
            }
        }
    }

out:
    blCleanup();
}

void blMain(uint32_t appBase)
{
    bool forceLoad = false;

    blLog("NanohubOS bootloader up @ %p\n", &blMain);

    //enter SPI loader if requested
    do {
        uint32_t res;
        struct OsUpdateHdr *os;

        blLoader(forceLoad);
        res = blVerifyOsUpdate(&os, NULL);
        if (res == OS_UPDT_SUCCESS)
            blApplyVerifiedUpdate(os);
        else if (res != OS_UPDT_HDR_CHECK_FAILED)
            blExtApiEraseSharedArea(BL_FLASH_KEY1, BL_FLASH_KEY2);

        forceLoad = true;
    } while (*(volatile uint32_t*)appBase == 0xFFFFFFFF);
}

const struct BlApiTable __attribute__((section(".blapi"))) __BL_API =
{
    .blGetVersion = &blExtApiGetVersion,
    .blReboot = &blExtApiReboot,
    .blGetSnum = &blExtApiGetSnum,
    .blProgramShared = &blExtApiProgramSharedArea,
    .blEraseShared = &blExtApiEraseSharedArea,
    .blProgramEe = &blExtApiProgramEe,
    .blGetPubKeysInfo = &blExtApiGetRsaKeyInfo,
    .blRsaPubOpIterative = &rsaPubOpIterative,
    .blSha2init = &sha2init,
    .blSha2processBytes = &sha2processBytes,
    .blSha2finish = &sha2finish,
    .blAesInitForEncr = &aesInitForEncr,
    .blAesInitForDecr = &aesInitForDecr,
    .blAesEncr = &aesEncr,
    .blAesDecr = &aesDecr,
    .blAesCbcInitForEncr = &aesCbcInitForEncr,
    .blAesCbcInitForDecr = &aesCbcInitForDecr,
    .blAesCbcEncr = &aesCbcEncr,
    .blAesCbcDecr = &aesCbcDecr,
    .blSigPaddingVerify = &blExtApiSigPaddingVerify,
    .blVerifyOsUpdate = &blExtApiVerifyOsUpdate,
};

Messung V0.5 in Prozent
C=90 H=94 G=91

¤ Dauer der Verarbeitung: 0.39 Sekunden  (vorverarbeitet am  2026-06-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik