summaryrefslogtreecommitdiff
path: root/src/include/s390_gcm.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/include/s390_gcm.h')
-rw-r--r--src/include/s390_gcm.h162
1 files changed, 162 insertions, 0 deletions
diff --git a/src/include/s390_gcm.h b/src/include/s390_gcm.h
index 3236d46..4f1d853 100644
--- a/src/include/s390_gcm.h
+++ b/src/include/s390_gcm.h
@@ -43,6 +43,32 @@ struct pad_meta {
uint64_t length_b;
} __attribute__((packed));
+/**
+ * GCM context struct
+ */
+struct kma_ctx_t {
+ unsigned char reserved[12];
+ uint32_t cv;
+ ica_aes_vector_t tag;
+ ica_aes_vector_t subkey_h;
+ uint64_t total_aad_length;
+ uint64_t total_input_length;
+ ica_aes_vector_t j0;
+ ica_aes_key_len_256_t key;
+ // Above this line: KMA parmblock, never change!
+ uint32_t version; /* 0x00 */
+ uint32_t direction;
+ uint32_t key_length;
+ uint32_t subkey_provided;
+ // Below this line: KMA simulation via MSA 4
+ unsigned char* iv;
+ uint32_t iv_length;
+ ica_aes_vector_t ucb;
+ uint32_t done;
+ uint32_t intermediate;
+ uint32_t first_time;
+} __attribute__((packed));
+
static inline int s390_ghash_hw(unsigned int fc,
const unsigned char *in_data,
unsigned long data_length,
@@ -591,4 +617,140 @@ static inline int s390_gcm_last(unsigned int function_code, unsigned char *icb,
tag, tag_length, 1, 1);
}
}
+
+static inline int is_valid_aes_key_length(unsigned int key_length)
+{
+ switch (key_length) {
+ case 16:
+ case 24:
+ case 32:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int is_valid_direction(unsigned int direction)
+{
+ switch (direction) {
+ case ICA_ENCRYPT:
+ case ICA_DECRYPT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int is_valid_tag_length(unsigned int tag_length)
+{
+ switch (tag_length) {
+ case 4:
+ case 8:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int s390_aes_gcm_simulate_kma_intermediate(const unsigned char *in_data,
+ unsigned char *out_data, unsigned long data_length,
+ const unsigned char *aad, unsigned long aad_length,
+ kma_ctx* ctx)
+{
+ int rc;
+ unsigned int function_code = aes_directed_fc(ctx->key_length, ctx->direction);
+
+ /* Add one to first counter value for MSA 4 code path. */
+ if (!ctx->first_time) {
+ memcpy(&(ctx->ucb), ctx->j0, AES_BLOCK_SIZE);
+ inc_ctr(ctx->ucb);
+ ctx->first_time = 1;
+ }
+
+ if (ctx->direction == ICA_ENCRYPT) {
+ rc = s390_gcm_intermediate(function_code, (unsigned char*)in_data, data_length, out_data,
+ (unsigned char*)&(ctx->ucb), (unsigned char*)aad, aad_length,
+ ctx->tag, AES_BLOCK_SIZE, (unsigned char*)ctx->key, (unsigned char*)ctx->subkey_h);
+ } else {
+ rc = s390_gcm_intermediate(function_code, out_data, data_length, (unsigned char*)in_data,
+ (unsigned char*)&(ctx->ucb), (unsigned char*)aad, aad_length,
+ ctx->tag, AES_BLOCK_SIZE, (unsigned char*)ctx->key, (unsigned char*)ctx->subkey_h);
+ }
+
+ if (rc)
+ return rc;
+
+ ctx->total_aad_length += aad_length;
+ ctx->total_input_length += data_length;
+
+ return 0;
+}
+
+static inline int s390_aes_gcm_simulate_kma_full(const unsigned char *in_data,
+ unsigned char *out_data, unsigned long data_length,
+ const unsigned char *aad, unsigned long aad_length,
+ kma_ctx* ctx)
+{
+ unsigned int function_code = aes_directed_fc(ctx->key_length, ctx->direction);
+
+ if (ctx->direction == ICA_ENCRYPT) {
+ return s390_gcm(function_code, (unsigned char*)in_data, data_length, out_data,
+ ctx->iv, ctx->iv_length, aad, aad_length,
+ ctx->tag, AES_BLOCK_SIZE, ctx->key);
+ } else {
+ return s390_gcm(function_code, out_data, data_length, (unsigned char*)in_data,
+ ctx->iv, ctx->iv_length, aad, aad_length,
+ ctx->tag, AES_BLOCK_SIZE, ctx->key);
+ }
+}
+
+static inline int s390_aes_gcm_kma(const unsigned char *in_data,
+ unsigned char *out_data, unsigned long data_length,
+ const unsigned char *aad, unsigned long aad_length,
+ unsigned int end_of_aad, unsigned int end_of_data,
+ kma_ctx* ctx)
+{
+ unsigned int function_code = aes_directed_fc(ctx->key_length, ctx->direction);
+ unsigned int hw_fc = 0;
+ int rc;
+
+ /* Set hardware function code */
+ if (*s390_kma_functions[function_code].enabled) {
+ hw_fc = s390_kma_functions[function_code].hw_fc;
+ if (ctx->subkey_provided)
+ hw_fc = hw_fc | HS_FLAG;
+ if (end_of_aad)
+ hw_fc = hw_fc | LAAD_FLAG;
+ if (end_of_data)
+ hw_fc = hw_fc | LPC_FLAG;
+ } else {
+ return EPERM;
+ }
+
+ if (!aad)
+ aad_length = 0;
+
+ if (!in_data || !out_data)
+ data_length = 0;
+
+ /* Actual lengths needed by KMA */
+ ctx->total_aad_length += aad_length*8;
+ ctx->total_input_length += data_length*8;
+
+ /* Call KMA */
+ rc = s390_kma(hw_fc, ctx,
+ out_data, in_data, data_length,
+ aad, aad_length);
+
+ if (rc >= 0) {
+ ctx->subkey_provided = 1;
+ return 0;
+ } else
+ return EIO;
+}
#endif