Ejemplo n.º 1
0
func s2v(key []byte, strings [][]byte) []byte {
	if len(key) == 0 {
		panic("Key must be non-empty.")
	}

	// RFC 5297 defines S2V to handle an empty array, but never actually uses it
	// that way for encryption or decryption. Additionally, the s2v_* reference
	// functions don't handle that case. So don't handle it here.
	if len(strings) == 0 {
		panic("strings must be non-empty.")
	}

	// siv_init requires a full SIV key, i.e. twice the length of the key used by
	// S2V. It uses the first half for the S2V key.
	tmpKey := make([]byte, 2*len(key))
	copy(tmpKey, key)
	key = tmpKey

	// Initialize the context struct.
	var ctx C.siv_ctx
	callResult := C.siv_init(&ctx, (*C.uchar)(&key[0]), C.int(8*len(key)))
	if callResult < 0 {
		panic("Error from siv_init.")
	}

	// Call s2v_update the requisite number of times.
	for i := 0; i < len(strings)-1; i++ {
		data := strings[i]
		dataLen := len(data)

		// Avoid indexing into an empty slice.
		if dataLen == 0 {
			data = make([]byte, 1)
		}

		C.s2v_update(&ctx, (*C.uchar)(&data[0]), C.int(dataLen))
	}

	// Now finalize with the last string. Avoid indexing into an empty slice.
	lastString := strings[len(strings)-1]
	lastStringLen := len(lastString)
	if lastStringLen == 0 {
		lastString = make([]byte, 1)
	}

	cDigest := (*C.uchar)(C.malloc(16))
	defer C.free(unsafe.Pointer(cDigest))

	callResult = C.s2v_final(
		&ctx,
		(*C.uchar)(&lastString[0]),
		C.int(lastStringLen),
		cDigest)

	if callResult < 0 {
		panic("Error from s2v_final.")
	}

	return C.GoBytes(unsafe.Pointer(cDigest), 16)
}
Ejemplo n.º 2
0
func encrypt(key, plaintext []byte, associated [][]byte) []byte {
	if len(key) == 0 {
		panic("Key must be non-empty.")
	}

	// Initialize the context struct.
	var ctx C.siv_ctx
	callResult := C.siv_init(&ctx, (*C.uchar)(&key[0]), C.int(8*len(key)))
	if callResult < 0 {
		panic("Error from siv_init.")
	}

	// Grab the right pointer for the plaintext, taking care not to index an
	// empty slice.
	var cPlaintext *C.uchar
	cPlaintextLen := C.int(len(plaintext))
	if cPlaintextLen > 0 {
		cPlaintext = (*C.uchar)(&plaintext[0])
	}

	// Create a buffer to store the SIV.
	cCounter := (*C.uchar)(C.malloc(16))
	defer C.free(unsafe.Pointer(cCounter))

	// Create associated data-related arguments. Take care not to index empty
	// slices.
	cNumAssociated := C.int(len(associated))

	adLens := make([]C.int, cNumAssociated)
	ads := make([]*C.uchar, cNumAssociated)
	if cNumAssociated == 0 {
		adLens = make([]C.int, 1)
		ads = make([]*C.uchar, 1)
	}

	for i, _ := range associated {
		aLen := len(associated[i])
		adLens[i] = C.int(aLen)

		if aLen > 0 {
			ads[i] = (*C.uchar)(&associated[i][0])
		}
	}

	cAdLens := (*C.int)(&adLens[0])
	cAds := (**C.uchar)(&ads[0])

	// Call siv_encrypt.
	cCiphertext := (*C.uchar)(C.malloc(C.size_t(cPlaintextLen)))
	defer C.free(unsafe.Pointer(cCiphertext))

	callResult = C.siv_encrypt(
		&ctx,
		cPlaintext,
		cCiphertext,
		cPlaintextLen,
		cCounter,
		cNumAssociated,
		cAdLens,
		cAds)

	if callResult < 0 {
		panic("Error from siv_encrypt.")
	}

	iv := C.GoBytes(unsafe.Pointer(cCounter), 16)
	ciphertext := C.GoBytes(unsafe.Pointer(cCiphertext), cPlaintextLen)

	return append(iv, ciphertext...)
}