implemented gcrypt RSA encrypt/decrypt operations
[strongswan.git] / src / libstrongswan / plugins / gcrypt / gcrypt_rsa_public_key.c
index bdb5d7f..909c43c 100644 (file)
@@ -65,7 +65,61 @@ bool gcrypt_rsa_build_keyids(gcry_sexp_t key, identification_t **keyid,
                                                         identification_t **keyid_info);
 
 /**
- * Verification of an EMPSA PKCS1 signature described in PKCS#1
+ * verification of a padded PKCS1 signature without an OID
+ */
+static bool verify_raw(private_gcrypt_rsa_public_key_t *this,
+                                                chunk_t data, chunk_t signature)
+{
+       gcry_sexp_t in, sig;
+       gcry_error_t err;
+       chunk_t em;
+       size_t k;
+       
+       /* EM = 0x00 || 0x01 || PS || 0x00 || T
+        * PS = 0xFF padding, with length to fill em
+        * T  = data
+        */
+       k = gcry_pk_get_nbits(this->key) / 8;
+       if (data.len > k - 3)
+       {
+               return FALSE;
+       }
+       em = chunk_alloc(k);
+       memset(em.ptr, 0xFF, em.len);
+       em.ptr[0] = 0x00;
+       em.ptr[1] = 0x01;
+       em.ptr[em.len - data.len - 1] = 0x00;
+       memcpy(em.ptr + em.len - data.len, data.ptr, data.len);
+       
+       err = gcry_sexp_build(&in, NULL, "(data(flags raw)(value %b))",
+                                                 em.len, em.ptr);
+       chunk_free(&em);
+       if (err)
+       {
+               DBG1("building data S-expression failed: %s", gpg_strerror(err));
+               return FALSE;
+       }
+       err = gcry_sexp_build(&sig, NULL, "(sig-val(rsa(s %b)))",
+                                                 signature.len, signature.ptr);
+       if (err)
+       {
+               DBG1("building signature S-expression failed: %s", gpg_strerror(err));
+               gcry_sexp_release(in);
+               return FALSE;
+       }
+       err = gcry_pk_verify(sig, in, this->key);
+       gcry_sexp_release(in);
+       gcry_sexp_release(sig);
+       if (err)
+       {
+               DBG1("RSA signature verification failed: %s", gpg_strerror(err));
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/**
+ * Verification of an EMSA PKCS1 signature described in PKCS#1
  */
 static bool verify_pkcs1(private_gcrypt_rsa_public_key_t *this,
                                                 hash_algorithm_t algorithm, char *hash_name,
@@ -128,6 +182,8 @@ static bool verify(private_gcrypt_rsa_public_key_t *this,
 {
        switch (scheme)
        {
+               case SIGN_RSA_EMSA_PKCS1_NULL:
+                       return verify_raw(this, data, signature);
                case SIGN_RSA_EMSA_PKCS1_MD5:
                        return verify_pkcs1(this, HASH_MD5, "md5", data, signature);
                case SIGN_RSA_EMSA_PKCS1_SHA1:
@@ -138,8 +194,6 @@ static bool verify(private_gcrypt_rsa_public_key_t *this,
                        return verify_pkcs1(this, HASH_SHA384, "sha384", data, signature);
                case SIGN_RSA_EMSA_PKCS1_SHA512:
                        return verify_pkcs1(this, HASH_SHA512, "sha512", data, signature);
-               case SIGN_DEFAULT:
-                       /* parsing hash OID currently not supported by gcrypt, fall */
                default:
                        DBG1("signature scheme %N not supported in RSA",
                                 signature_scheme_names, scheme);
@@ -148,13 +202,33 @@ static bool verify(private_gcrypt_rsa_public_key_t *this,
 }
 
 /**
- * Implementation of public_key_t.get_keysize.
+ * Implementation of public_key_t.encrypt.
  */
-static bool encrypt_(private_gcrypt_rsa_public_key_t *this, chunk_t crypto,
-                                       chunk_t *plain)
+static bool encrypt_(private_gcrypt_rsa_public_key_t *this, chunk_t plain,
+                                        chunk_t *encrypted)
 {
-       DBG1("RSA public key encryption not implemented");
-       return FALSE;
+       gcry_sexp_t in, out;
+       gcry_error_t err;
+       
+       /* "pkcs1" uses PKCS 1.5 (section 8.1) block type 2 encryption:
+        * 00 | 02 | RANDOM | 00 | DATA */
+       err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(value %b))",
+                                                 plain.len, plain.ptr);
+       if (err)
+       {
+               DBG1("building encryption S-expression failed: %s", gpg_strerror(err));
+               return FALSE;
+       }
+       err = gcry_pk_encrypt(&out, in, this->key);
+       gcry_sexp_release(in);
+       if (err)
+       {
+               DBG1("encrypting data using pkcs1 failed: %s", gpg_strerror(err));
+               return FALSE;
+       }
+       *encrypted = gcrypt_rsa_find_token(out, "a");
+       gcry_sexp_release(out);
+       return !!encrypted->len;
 }
 
 /**