Esempio n. 1
0
func (ctx *cipherCtx) applyKeyAndIV(key, iv []byte) error {
	var kptr, iptr *C.uchar
	if key != nil {
		if len(key) != ctx.KeySize() {
			return fmt.Errorf("bad key size (%d bytes instead of %d)",
				len(key), ctx.KeySize())
		}
		kptr = (*C.uchar)(&key[0])
	}
	if iv != nil {
		if len(iv) != ctx.IVSize() {
			return fmt.Errorf("bad IV size (%d bytes instead of %d)",
				len(iv), ctx.IVSize())
		}
		iptr = (*C.uchar)(&iv[0])
	}
	if kptr != nil || iptr != nil {
		var res C.int
		if ctx.ctx.encrypt != 0 {
			res = C.EVP_EncryptInit_ex(ctx.ctx, nil, nil, kptr, iptr)
		} else {
			res = C.EVP_DecryptInit_ex(ctx.ctx, nil, nil, kptr, iptr)
		}
		if 1 != res {
			return errors.New("failed to apply key/IV")
		}
	}
	return nil
}
Esempio n. 2
0
func newDecryptionCipherCtx(c *Cipher, e *Engine, key, iv []byte) (
	*decryptionCipherCtx, error) {
	if c == nil {
		return nil, errors.New("null cipher not allowed")
	}
	ctx, err := newCipherCtx()
	if err != nil {
		return nil, err
	}
	var eptr *C.ENGINE
	if e != nil {
		eptr = e.e
	}
	if 1 != C.EVP_DecryptInit_ex(ctx.ctx, c.ptr, eptr, nil, nil) {
		return nil, errors.New("failed to initialize cipher context")
	}
	err = ctx.applyKeyAndIV(key, iv)
	if err != nil {
		return nil, err
	}
	return &decryptionCipherCtx{cipherCtx: ctx}, nil
}
Esempio n. 3
0
func NewGCMDecryptionCipherCtx(blocksize int, e *Engine, key, iv []byte) (
	AuthenticatedDecryptionCipherCtx, error) {
	cipher, err := getGCMCipher(blocksize)
	if err != nil {
		return nil, err
	}
	ctx, err := newDecryptionCipherCtx(cipher, e, key, nil)
	if err != nil {
		return nil, err
	}
	if iv != nil {
		err := ctx.setCtrl(C.EVP_CTRL_GCM_SET_IVLEN, len(iv))
		if err != nil {
			return nil, fmt.Errorf("could not set IV len to %d: %s",
				len(iv), err)
		}
		if 1 != C.EVP_DecryptInit_ex(ctx.ctx, nil, nil, nil,
			(*C.uchar)(&iv[0])) {
			return nil, errors.New("failed to apply IV")
		}
	}
	return &authDecryptionCipherCtx{decryptionCipherCtx: ctx}, nil
}
Esempio n. 4
0
//export ticket_key_cb_thunk
func ticket_key_cb_thunk(p unsafe.Pointer, s *C.SSL, key_name *C.uchar,
	iv *C.uchar, cctx *C.EVP_CIPHER_CTX, hctx *C.HMAC_CTX, enc C.int) C.int {

	// no panic's allowed. it's super hard to guarantee any state at this point
	// so just abort everything.
	defer func() {
		if err := recover(); err != nil {
			logger.Critf("openssl: ticket key callback panic'd: %v", err)
			os.Exit(1)
		}
	}()

	ctx := (*Ctx)(p)
	store := ctx.ticket_store
	if store == nil {
		// TODO(jeff): should this be an error condition? it doesn't make sense
		// to be called if we don't have a store I believe, but that's probably
		// not worth aborting the handshake which is what I believe returning
		// an error would do.
		return ticket_resp_requireHandshake
	}

	ctx.ticket_store_mu.Lock()
	defer ctx.ticket_store_mu.Unlock()

	switch enc {
	case ticket_req_newSession:
		key := store.Keys.Current()
		if key == nil {
			key = store.Keys.New()
			if key == nil {
				return ticket_resp_requireHandshake
			}
		}

		C.memcpy(
			unsafe.Pointer(key_name),
			unsafe.Pointer(&key.Name[0]),
			KeyNameSize)
		C.EVP_EncryptInit_ex(
			cctx,
			store.CipherCtx.Cipher.ptr,
			store.cipherEngine(),
			(*C.uchar)(&key.CipherKey[0]),
			(*C.uchar)(&key.IV[0]))
		C.HMAC_Init_ex(
			hctx,
			unsafe.Pointer(&key.HMACKey[0]),
			C.int(len(key.HMACKey)),
			store.DigestCtx.Digest.ptr,
			store.digestEngine())

		return ticket_resp_sessionOk

	case ticket_req_lookupSession:
		var name TicketName
		C.memcpy(
			unsafe.Pointer(&name[0]),
			unsafe.Pointer(key_name),
			KeyNameSize)

		key := store.Keys.Lookup(name)
		if key == nil {
			return ticket_resp_requireHandshake
		}
		if store.Keys.Expired(name) {
			return ticket_resp_requireHandshake
		}

		C.EVP_DecryptInit_ex(
			cctx,
			store.CipherCtx.Cipher.ptr,
			store.cipherEngine(),
			(*C.uchar)(&key.CipherKey[0]),
			(*C.uchar)(&key.IV[0]))
		C.HMAC_Init_ex(
			hctx,
			unsafe.Pointer(&key.HMACKey[0]),
			C.int(len(key.HMACKey)),
			store.DigestCtx.Digest.ptr,
			store.digestEngine())

		if store.Keys.ShouldRenew(name) {
			return ticket_resp_renewSession
		}

		return ticket_resp_sessionOk

	default:
		return ticket_resp_error
	}
}
Esempio n. 5
0
// Open decrypts "in" using "iv" and "authData" and append the result to "dst"
func (g stupidGCM) Open(dst, iv, in, authData []byte) ([]byte, error) {
	if len(iv) != ivLen {
		log.Panicf("Only %d-byte IVs are supported", ivLen)
	}
	if len(in) <= tagLen {
		log.Panic("Input data too short")
	}
	buf := make([]byte, len(in)-tagLen)
	ciphertext := in[:len(in)-tagLen]
	tag := in[len(in)-tagLen:]

	// https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_GCM_mode

	// Create scratch space "context"
	ctx := C.EVP_CIPHER_CTX_new()
	if ctx == nil {
		log.Panic("EVP_CIPHER_CTX_new failed")
	}

	// Set cipher to AES-256
	if C.EVP_DecryptInit_ex(ctx, C.EVP_aes_256_gcm(), nil, nil, nil) != 1 {
		log.Panic("EVP_DecryptInit_ex I failed")
	}

	// Use 16-byte IV
	if C.EVP_CIPHER_CTX_ctrl(ctx, C.EVP_CTRL_GCM_SET_IVLEN, ivLen, nil) != 1 {
		log.Panic("EVP_CIPHER_CTX_ctrl EVP_CTRL_GCM_SET_IVLEN failed")
	}

	// Set key and IV
	if C.EVP_DecryptInit_ex(ctx, nil, nil, (*C.uchar)(&g.key[0]), (*C.uchar)(&iv[0])) != 1 {
		log.Panic("EVP_DecryptInit_ex II failed")
	}

	// Set expected GMAC tag
	if C.EVP_CIPHER_CTX_ctrl(ctx, C.EVP_CTRL_GCM_SET_TAG, tagLen, (unsafe.Pointer)(&tag[0])) != 1 {
		log.Panic("EVP_CIPHER_CTX_ctrl failed")
	}

	// Provide authentication data
	var resultLen C.int
	if C.EVP_DecryptUpdate(ctx, nil, &resultLen, (*C.uchar)(&authData[0]), C.int(len(authData))) != 1 {
		log.Panic("EVP_DecryptUpdate authData failed")
	}
	if int(resultLen) != len(authData) {
		log.Panicf("Unexpected length %d", resultLen)
	}

	// Decrypt "ciphertext" into "buf"
	if C.EVP_DecryptUpdate(ctx, (*C.uchar)(&buf[0]), &resultLen, (*C.uchar)(&ciphertext[0]), C.int(len(ciphertext))) != 1 {
		log.Panic("EVP_DecryptUpdate failed")
	}
	if int(resultLen) != len(ciphertext) {
		log.Panicf("Unexpected length %d", resultLen)
	}

	// Check GMAC
	dummy := make([]byte, 16)
	res := C.EVP_DecryptFinal_ex(ctx, (*C.uchar)(&dummy[0]), &resultLen)
	if resultLen != 0 {
		log.Panicf("Unexpected length %d", resultLen)
	}

	// Free scratch space
	C.EVP_CIPHER_CTX_free(ctx)

	if res != 1 {
		return nil, fmt.Errorf("stupidgcm: message authentication failed")
	}

	return append(dst, buf...), nil
}