summaryrefslogtreecommitdiffstats
path: root/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample2/index.rst
blob: 76f6c21d8f5b30956c3265631db791cf645e02d4 (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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
.. _mozilla_projects_nss_nss_sample_code_nss_sample_code_sample2:

NSS Sample Code sample2
=======================

.. _nss_sample_code_2_symmetric_encryption:

`NSS Sample Code 2: Symmetric Encryption <#nss_sample_code_2_symmetric_encryption>`__
-------------------------------------------------------------------------------------

.. container::

   .. code::

      /* Example code to illustrate DES enccryption/decryption using NSS.
       * The example skips the details of obtaining the Key & IV to use, and
       * just uses a hardcoded Key & IV.
       * Note: IV is only needed if Cipher Blocking Chaining (CBC) mode of encryption
       *       is used
       *
       * The recommended approach is to store and transport WRAPPED (encrypted)
       * DES Keys (IVs can be in the clear). However, it is a common (and dangerous)
       * practice to use raw DES Keys. This example shows the use of a RAW key.
       */


      #include "nss.h"
      #include "pk11pub.h"

      /* example Key & IV */
      unsigned char gKey[] = {0xe8, 0xa7, 0x7c, 0xe2, 0x05, 0x63, 0x6a, 0x31};
      unsigned char gIV[] = {0xe4, 0xbb, 0x3b, 0xd3, 0xc3, 0x71, 0x2e, 0x58};

      int main(int argc, char **argv)
      {
        CK_MECHANISM_TYPE  cipherMech;
        PK11SlotInfo*      slot = NULL;
        PK11SymKey*        SymKey = NULL;
        SECItem*           SecParam = NULL;
        PK11Context*       EncContext = NULL;
        SECItem            keyItem, ivItem;
        SECStatus          rv, rv1, rv2;
        unsigned char      data[1024], buf1[1024], buf2[1024];
        int                i, result_len, tmp1_outlen, tmp2_outlen;

        /* Initialize NSS
         * If your application code has already initialized NSS, you can skip it
         * here.
         * This code uses the simplest of the Init functions, which does not
         * require a NSS database to exist
         */
        rv = NSS_NoDB_Init(".");
        if (rv != SECSuccess)
        {
          fprintf(stderr, "NSS initialization failed (err %d)\n",
                  PR_GetError());
          goto out;
        }

        /* choose mechanism: CKM_DES_CBC_PAD, CKM_DES3_ECB, CKM_DES3_CBC.....
         * Note that some mechanisms (*_PAD) imply the padding is handled for you
         * by NSS. If you choose something else, then data padding is the
         * application's responsibility
         */
        cipherMech = CKM_DES_CBC_PAD;
        slot = PK11_GetBestSlot(cipherMech, NULL);
        /* slot = PK11_GetInternalKeySlot(); is a simpler alternative but in
         * theory, it *may not* return the optimal slot for the operation. For
         * DES ops, Internal slot is typically the best slot
         */
        if (slot == NULL)
        {
          fprintf(stderr, "Unable to find security device (err %d)\n",
                  PR_GetError());
          goto out;
        }

        /* NSS passes blobs around as SECItems. These contain a pointer to
         * data and a length. Turn the raw key into a SECItem. */
        keyItem.type = siBuffer;
        keyItem.data = gKey;
        keyItem.len = sizeof(gKey);

        /* Turn the raw key into a key object. We use PK11_OriginUnwrap
         * to indicate the key was unwrapped - which is what should be done
         * normally anyway - using raw keys isn't a good idea */
        SymKey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, CKA_ENCRYPT,
                                   &keyItem, NULL);
        if (SymKey == NULL)
        {
          fprintf(stderr, "Failure to import key into NSS (err %d)\n",
                  PR_GetError());
          goto out;
        }

        /* set up the PKCS11 encryption parameters.
         * when not using CBC mode, ivItem.data and ivItem.len can be 0, or you
         * can simply pass NULL for the iv parameter in PK11_ParamFromIV func
         */
        ivItem.type = siBuffer;
        ivItem.data = gIV;
        ivItem.len = sizeof(gIV);
        SecParam = PK11_ParamFromIV(cipherMech, &ivItem);
        if (SecParam == NULL)
        {
          fprintf(stderr, "Failure to set up PKCS11 param (err %d)\n",
                  PR_GetError());
          goto out;
        }

        /* sample data we'll encrypt and decrypt */
        strcpy(data, "Encrypt me!");
        fprintf(stderr, "Clear Data: %s\n", data);

        /* ========================= START SECTION ============================= */
        /* If using the same key and iv over and over, stuff before this         */
        /* section and after this section needs to be done only ONCE             */

        /* ENCRYPT data into buf1. buf1 len must be atleast (data len + 8) */
        tmp1_outlen = tmp2_outlen = 0;

        /* Create cipher context */
        EncContext = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT,
                                                SymKey, SecParam);
        rv1 = PK11_CipherOp(EncContext, buf1, &tmp1_outlen, sizeof(buf1),
                            data, strlen(data)+1);
        rv2 = PK11_DigestFinal(EncContext, buf1+tmp1_outlen, &tmp2_outlen,
                               sizeof(buf1)-tmp1_outlen);
        PK11_DestroyContext(EncContext, PR_TRUE);
        result_len = tmp1_outlen + tmp2_outlen;
        if (rv1 != SECSuccess || rv2 != SECSuccess)
          goto out;

        fprintf(stderr, "Encrypted Data: ");
        for (i=0; i<result_len; i++)
          fprintf(stderr, "%02x ", buf1[i]);
        fprintf(stderr, "\n");


        /* DECRYPT buf1 into buf2. buf2 len must be atleast buf1 len */
        tmp1_outlen = tmp2_outlen = 0;

        /* Create cipher context */
        EncContext = PK11_CreateContextBySymKey(cipherMech, CKA_DECRYPT,
                                                SymKey, SecParam);
        rv1 = PK11_CipherOp(EncContext, buf2, &tmp1_outlen, sizeof(buf2),
                            buf1, result_len);
        rv2 = PK11_DigestFinal(EncContext, buf2+tmp1_outlen, &tmp2_outlen,
                               result_len-tmp1_outlen);
        PK11_DestroyContext(EncContext, PR_TRUE);
        result_len = tmp1_outlen + tmp2_outlen;
        if (rv1 != SECSuccess || rv2 != SECSuccess)
          goto out;

        fprintf(stderr, "Decrypted Data: %s\n", buf2);

        /* =========================== END SECTION ============================= */


      out:
        if (SymKey)
          PK11_FreeSymKey(SymKey);
        if (SecParam)
          SECITEM_FreeItem(SecParam, PR_TRUE);

      }