int c1s1::calc_c1_digest(char *&digest)
{
    int ret = ERROR_SUCCESS;

    mAssert(schema == srs_schema0 || schema == srs_schema1);

    char *c1s1_joined_bytes = NULL;

    if (schema == srs_schema0) {
        c1s1_joined_bytes = srs_bytes_join_schema0(time, version, &block0.key, &block1.digest);
    } else {
        c1s1_joined_bytes = srs_bytes_join_schema1(time, version, &block0.digest, &block1.key);
    }

    mAssert(c1s1_joined_bytes != NULL);
    mAutoFreeArray(char, c1s1_joined_bytes);

    digest = new char[OpensslHashSize];
    if ((ret = openssl_HMACsha256(c1s1_joined_bytes, 1536 - 32, SrsGenuineFPKey, 30, digest)) != ERROR_SUCCESS) {
        log_error("calc digest for c1 failed. ret=%d", ret);
        return ret;
    }
    log_verbose("digest calculated for c1");

    return ret;
}
MAMF0Any *MAMFObject::value(int index)
{
    mAssert(index < (int)values.size());

    pair<MString, MAMF0Any *> &p = values.at(index);
    return p.second;
}
MString MAMFObject::key(int index)
{
    mAssert(index < (int)values.size());

    pair<MString, MAMF0Any *> &p = values.at(index);
    return p.first;
}
void srs_schema1_copy_to(char *bytes, bool with_digest,
                         int32_t time, int32_t version, digest_block *digest, key_block *key)
{
    char *pp = bytes;

    __srs_time_copy_to(pp, time);
    __srs_version_copy_to(pp, version);
    __srs_digest_copy_to(pp, digest, with_digest);
    __srs_key_copy_to(pp, key);

    if (with_digest) {
        mAssert(pp - bytes == 1536);
    } else {
        mAssert(pp - bytes == 1536 - 32);
    }
}
// parse digest block from c1s1.
// if created, user must free it by srs_digest_block_free
// @c1s1_digest_bytes the digest start bytes, maybe c1s1 or c1s1+764
int srs_digest_block_parse(digest_block *digest, char *c1s1_digest_bytes)
{
    int ret = ERROR_SUCCESS;

    char *pp = c1s1_digest_bytes;

    digest->offset = *(int32_t *)pp;
    pp += sizeof(int32_t);

    digest->random0 = NULL;
    digest->random1 = NULL;

    int offset = srs_digest_block_get_offset(digest);
    mAssert(offset >= 0);

    digest->random0_size = offset;
    if (digest->random0_size > 0) {
        digest->random0 = new char[digest->random0_size];
        memcpy(digest->random0, pp, digest->random0_size);
    }
    pp += digest->random0_size;

    memcpy(digest->digest, pp, sizeof(digest->digest));
    pp += sizeof(digest->digest);

    digest->random1_size = 764 - 4 - offset - 32;
    if (digest->random1_size > 0) {
        digest->random1 = new char[digest->random1_size];
        memcpy(digest->random1, pp, digest->random1_size);
    }

    return ret;
}
// parse key block from c1s1.
// if created, user must free it by srs_key_block_free
// @c1s1_key_bytes the key start bytes, maybe c1s1 or c1s1+764
int srs_key_block_parse(key_block *key, char *c1s1_key_bytes)
{
    int ret = ERROR_SUCCESS;

    char *pp = c1s1_key_bytes + 764;

    pp -= sizeof(int32_t);
    key->offset = *(int32_t *)pp;

    key->random0 = NULL;
    key->random1 = NULL;

    int offset = srs_key_block_get_offset(key);
    mAssert(offset >= 0);

    pp = c1s1_key_bytes;
    key->random0_size = offset;
    if (key->random0_size > 0) {
        key->random0 = new char[key->random0_size];
        memcpy(key->random0, pp, key->random0_size);
    }
    pp += key->random0_size;

    memcpy(key->key, pp, sizeof(key->key));
    pp += sizeof(key->key);

    key->random1_size = 764 - offset - 128 - 4;
    if (key->random1_size > 0) {
        key->random1 = new char[key->random1_size];
        memcpy(key->random1, pp, key->random1_size);
    }

    return ret;
}
int c1s1::s1_create(c1s1* c1,u_int8_t *&shared_key)
{
    int ret = ERROR_SUCCESS;

    if (c1->schema == srs_schema_invalid) {
        ret = ERROR_RTMP_CH_SCHEMA;
        log_error("create s1 failed. invalid schema=%d, ret=%d", c1->schema, ret);
        return ret;
    }

    destroy_blocks();
    schema = c1->schema;

    time = ::time(NULL);
    version = 0x01000504; // server s1 version

    if (schema == srs_schema0) {
        srs_key_block_init(&block0.key);
        srs_digest_block_init(&block1.digest);
    } else {
        srs_digest_block_init(&block0.digest);
        srs_key_block_init(&block1.key);
    }

    if (schema == srs_schema0) {
        if ((ret = openssl_generate_key(c1->block0.key.key, block0.key.key, 128,shared_key)) != ERROR_SUCCESS) {
            log_error("calc s1 key failed. ret=%d", ret);
            return ret;
        }
    } else {
        if ((ret = openssl_generate_key(c1->block1.key.key, block1.key.key, 128,shared_key)) != ERROR_SUCCESS) {
            log_error("calc s1 key failed. ret=%d", ret);
            return ret;
        }
    }
    log_verbose("calc s1 key success.");

    char *s1_digest = NULL;
    if ((ret = calc_s1_digest(s1_digest))  != ERROR_SUCCESS) {
        log_error("calc s1 digest failed. ret=%d", ret);
        return ret;
    }
    log_verbose("calc s1 digest success.");

    mAssert(s1_digest != NULL);
    mAutoFreeArray(char, s1_digest);

    if (schema == srs_schema0) {
        memcpy(block1.digest.digest, s1_digest, 32);
    } else {
        memcpy(block0.digest.digest, s1_digest, 32);
    }
    log_verbose("copy s1 key success.");

    return ret;
}
void c1s1::dump(char *_c1s1)
{
    mAssert(schema != srs_schema_invalid);

    if (schema == srs_schema0) {
        srs_schema0_copy_to(_c1s1, true, time, version, &block0.key, &block1.digest);
    } else {
        srs_schema1_copy_to(_c1s1, true, time, version, &block0.digest, &block1.key);
    }
}
char *c1s1::get_digest()
{
    mAssert(schema != srs_schema_invalid);

    if (schema == srs_schema0) {
        return block1.digest.digest;
    } else {
        return block0.digest.digest;
    }
}
int c1s1::c1_create(srs_schema_type _schema)
{
    int ret = ERROR_SUCCESS;

    if (_schema == srs_schema_invalid) {
        ret = ERROR_RTMP_CH_SCHEMA;
        log_error("create c1 failed. invalid schema=%d, ret=%d", _schema, ret);
        return ret;
    }

    destroy_blocks();

    time = ::time(NULL);
    // client c1 version
    char *_version = (char *)&version;
    _version[0] = 10;
    _version[1] = 0;
    _version[2] = 45;
    _version[3] = 2;

    if (_schema == srs_schema0) {
        srs_key_block_init(&block0.key);
        srs_digest_block_init(&block1.digest);
    } else {
        srs_digest_block_init(&block0.digest);
        srs_key_block_init(&block1.key);
    }

    schema = _schema;

    char *digest = NULL;

    if ((ret = calc_c1_digest(digest)) != ERROR_SUCCESS) {
        log_error("sign c1 error, failed to calc digest. ret=%d", ret);
        return ret;
    }

    mAssert(digest != NULL);
    mAutoFreeArray(char, digest);

    if (schema == srs_schema0) {
        memcpy(block1.digest.digest, digest, 32);
    } else {
        memcpy(block0.digest.digest, digest, 32);
    }

    return ret;
}
int c1s1::s1_validate_digest(bool& is_valid)
{
    int ret = ERROR_SUCCESS;

    char* c1_digest = NULL;

    if ((ret = calc_s1_digest(c1_digest)) != ERROR_SUCCESS) {
        log_error("validate c1 error, failed to calc digest. ret=%d", ret);
        return ret;
    }

    mAssert(c1_digest != NULL);
    mAutoFreeArray(char, c1_digest);

    if (schema == srs_schema0) {
        is_valid = srs_bytes_equals(block1.digest.digest, c1_digest, 32);
    } else {
        is_valid = srs_bytes_equals(block0.digest.digest, c1_digest, 32);
    }

    return ret;
}
// create new digest block data.
// if created, user must free it by srs_digest_block_free
void srs_digest_block_init(digest_block *digest)
{
    digest->offset = (int32_t)rand();
    digest->random0 = NULL;
    digest->random1 = NULL;

    int offset = srs_digest_block_get_offset(digest);
    mAssert(offset >= 0);

    digest->random0_size = offset;
    if (digest->random0_size > 0) {
        digest->random0 = new char[digest->random0_size];
        srs_random_generate(digest->random0, digest->random0_size);
    }

    srs_random_generate(digest->digest, sizeof(digest->digest));

    digest->random1_size = 764 - 4 - offset - 32;
    if (digest->random1_size > 0) {
        digest->random1 = new char[digest->random1_size];
        srs_random_generate(digest->random1, digest->random1_size);
    }
}
// create new key block data.
// if created, user must free it by srs_key_block_free
void srs_key_block_init(key_block *key)
{
    key->offset = (int32_t)rand();
    key->random0 = NULL;
    key->random1 = NULL;

    int offset = srs_key_block_get_offset(key);
    mAssert(offset >= 0);

    key->random0_size = offset;
    if (key->random0_size > 0) {
        key->random0 = new char[key->random0_size];
        srs_random_generate(key->random0, key->random0_size);
    }

    srs_random_generate(key->key, sizeof(key->key));

    key->random1_size = 764 - offset - 128 - 4;
    if (key->random1_size > 0) {
        key->random1 = new char[key->random1_size];
        srs_random_generate(key->random1, key->random1_size);
    }
}