summaryrefslogtreecommitdiff
path: root/lib/x509/pkcs12_encr.c
blob: f8f232050b8630c04510f84b8036526452eb8433 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* Taken from minip12
 */

#include <gnutls_int.h>

#ifdef ENABLE_PKI

#include <gcrypt.h>
#include <gnutls_errors.h>
#include <ctype.h>

/* Returns 0 if the password is ok, or a negative error
 * code instead.
 */
int _pkcs12_check_pass( const char* pass, size_t plen) 
{
const unsigned char* p = pass;
int i;

	for (i=0;i<plen;i++) {
		if ( p[i] < 128) continue;
		return GNUTLS_E_INVALID_PASSWORD;
	}
	
	return 0;
}

int 
_pkcs12_string_to_key (int id, const char *salt, int salt_size, int iter, const char *pw,
               int req_keylen, unsigned char *keybuf)
{
  int rc, i, j;
  GcryMDHd md;
  GcryMPI num_b1 = NULL;
  int pwlen;
  unsigned char hash[20], buf_b[64], buf_i[128], *p;
  size_t cur_keylen;
  size_t n;

  cur_keylen = 0;
  pwlen = strlen (pw);
  if (pwlen > 63/2 || salt_size > 8) {
      gnutls_assert();
      return GNUTLS_E_INVALID_REQUEST;
  }

  if ((rc=_pkcs12_check_pass( pw, pwlen)) < 0) {
  	gnutls_assert();
  	return rc;
  }

  /* Store salt and password in BUF_I */
  p = buf_i;
  for(i=0; i < 64; i++)
    *p++ = salt [i%8];
  for(i=j=0; i < 64; i += 2)
    {
      *p++ = 0;
      *p++ = pw[j];
      if (++j > pwlen) /* Note, that we include the trailing zero */
        j = 0;
    }

  for (;;)
    {
      md = gcry_md_open (GCRY_MD_SHA1, 0);
      if (!md)
        {
          return GNUTLS_E_DECRYPTION_FAILED;
        }
      for(i=0; i < 64; i++)
        gcry_md_putc (md, id);
      gcry_md_write (md, buf_i, 128);
      memcpy (hash, gcry_md_read (md, 0), 20);
      gcry_md_close (md);
      for (i=1; i < iter; i++)
        gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash, 20);

      for (i=0; i < 20 && cur_keylen < req_keylen; i++)
        keybuf[cur_keylen++] = hash[i];
      if (cur_keylen == req_keylen)
        {
          gcry_mpi_release (num_b1);
          return 0; /* ready */
        }
      
      /* need more bytes. */
      for(i=0; i < 64; i++)
        buf_b[i] = hash[i % 20];
      n = 64;
      rc = gcry_mpi_scan (&num_b1, GCRYMPI_FMT_USG, buf_b, &n);
      if (rc)
        {
          return GNUTLS_E_DECRYPTION_FAILED;
        }
      gcry_mpi_add_ui (num_b1, num_b1, 1);
      for (i=0; i < 128; i += 64)
        {
          GcryMPI num_ij;

          n = 64;
          rc = gcry_mpi_scan (&num_ij, GCRYMPI_FMT_USG, buf_i + i, &n);
          if (rc)
            {
              return GNUTLS_E_DECRYPTION_FAILED;
            }
          gcry_mpi_add (num_ij, num_ij, num_b1);
          gcry_mpi_clear_highbit (num_ij, 64*8);
          n = 64;
          rc = gcry_mpi_print (GCRYMPI_FMT_USG, buf_i + i, &n, num_ij);
          if (rc)
            {
              return GNUTLS_E_DECRYPTION_FAILED;
            }
          gcry_mpi_release (num_ij);
        }
    }
}

#endif /* ENABLE_PKI */