void SocketOutputStream::writeDouble(double data)
{
#if CLIENT_BYTE_ORDER != SERVER_BYTE_ORDER
    data = _OSSwapInt64(data);
#endif
    this->write((const char *)(&data), sizeof(double));
}
void SocketOutputStream::writeLonglong(int64_t data)
{
#if CLIENT_BYTE_ORDER != SERVER_BYTE_ORDER
    data = _OSSwapInt64(data);
#endif
    this->write((const char *)(&data), sizeof(int64_t));
}
int  
CCSymmetricKeyUnwrap( CCWrappingAlgorithm algorithm, 
					 const uint8_t *iv, const size_t ivLen,
					 const uint8_t *kek, size_t kekLen,
					 const uint8_t  *wrappedKey, size_t wrappedKeyLen,
					 uint8_t  *rawKey, size_t *rawKeyLen)
{
    uint32_t n = wrappedKeyLen/8 - 1; /* raw key size in 64 bit blocks */
    uint64_t (*R)[2]; /* R is a two-dimensional array, with n rows of 2 columns */
    int i, j, err;

	// allocate R
	R = calloc(n, sizeof(uint64_t[2])); 
    require_action(R, out, err = -1);
	// kek multiple of 64 bits: 128, 192, 256
    require_action(kekLen == 16 || kekLen == 32, out, err = -1);
    // wrapped_key_len 64 bits larger than key_len
    require_action(rawKeyLen && (*rawKeyLen >= wrappedKeyLen - 64/8), out, err = -1);

    // R[0][1] = C[0] ... R[1][n-1] = C[n-1]
    memcpy(&R[0][0], wrappedKey, 64/8); 
    for (i = 0; i < n; i++)
        memcpy(&R[i][1], wrappedKey + (64/8) * (i+1), 64/8);

    for (j = 5; j >= 0; j--) {
        for (i = n - 1; i >= 0; i--)
        {
           R[i][0] = R[(i + 1) % n][0] ^ _OSSwapInt64((n*j)+i+1);
            require_action(aes_operation(false, kek, kekLen, (uint8_t*)&R[i][0]), out, err = -1);
        }
    }

	uint64_t kek_iv = pack64(iv, ivLen);

    // R[0][0] == iv?
    require_action(R[0][0] == kek_iv, out, err = -1);

    // write output
    for (i = 0; i < n; i++)
        memcpy(rawKey + i * 8, &R[i][1], 8);

    // clean all stack variables

    err = 0;
    
out:
	if (R) free(R);
    return err;
}
int  
CCSymmetricKeyWrap( CCWrappingAlgorithm algorithm, 
				   const uint8_t *iv, const size_t ivLen,
				   const uint8_t *kek, size_t kekLen,
				   const uint8_t *rawKey, size_t rawKeyLen,
				   uint8_t  *wrappedKey, size_t *wrappedKeyLen)
{
    uint32_t n = rawKeyLen / 8; /* key size in 64 bit blocks */
    uint64_t (*R)[2]; /* R is a two-dimensional array, with n rows of 2 columns */
    int i, j, err;
	
	// allocate R
	R = calloc(n, sizeof(uint64_t[2])); 
    require_action(R, out, err = -1);
    // don't wrap with something smaller
    require_action(rawKeyLen >= kekLen, out, err = -1);
    // kek multiple of 64 bits: 128, 192, 256
    require_action(kekLen == 16 || kekLen == 24 || kekLen == 32, out, err = -1);
    // wrapped_key_len 64 bits larger than key_len
    require_action(wrappedKeyLen && (*wrappedKeyLen >= rawKeyLen + 64/8), out, err = -1);

    // R[0][1] = P[0] ... R[1][n-1] = P[n-1]
    for (i = 0; i < n; i++)
        memcpy(&R[i][1], rawKey + (64/8) * i, (64/8));

	uint64_t kek_iv = pack64(iv, ivLen);
	
    R[0][0] = kek_iv;

    for (j = 0; j < 6; j++) {
        for (i = 0; i < n; i++)
        {
            require_action(aes_operation(true, kek, kekLen, (uint8_t*)&R[i][0]), out, err = -1);
            R[(i + 1) % n][0] = R[i][0] ^ _OSSwapInt64((n*j)+i+1);
        }
    }
	
    // write output
    memcpy(wrappedKey, &R[0][0], 8);
    for (i = 0; i < n; i++)
        memcpy(wrappedKey + 8 + i * 8, &R[i][1], 8);

    err = 0;
out:
    if (R) free(R);
    return err;
}