Completed
Push — master ( 610c21...319146 )
by Florent
02:34
created

AESGCMKW::encryptKey()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 3 Features 0
Metric Value
c 5
b 3
f 0
dl 0
loc 19
rs 9.4285
cc 2
eloc 13
nc 2
nop 4
1
<?php
2
3
/*
4
 * The MIT License (MIT)
5
 *
6
 * Copyright (c) 2014-2016 Spomky-Labs
7
 *
8
 * This software may be modified and distributed under the terms
9
 * of the MIT license.  See the LICENSE file for details.
10
 */
11
12
namespace Jose\Algorithm\KeyEncryption;
13
14
use Base64Url\Base64Url;
15
use Crypto\Cipher;
16
use Jose\Object\JWKInterface;
17
use Jose\Util\GCM;
18
use Jose\Util\StringUtil;
19
20
/**
21
 * Class AESGCMKW.
22
 */
23
abstract class AESGCMKW implements KeyWrappingInterface
24
{
25
    /**
26
     * {@inheritdoc}
27
     */
28
    public function wrapKey(JWKInterface $key, $cek, array $complete_headers, array &$additional_headers)
29
    {
30
        $this->checkKey($key);
31
        $iv = StringUtil::generateRandomBytes(96 / 8);
32
        $additional_headers['iv'] = Base64Url::encode($iv);
33
34
        if (class_exists('\Crypto\Cipher')) {
35
            $cipher = Cipher::aes(Cipher::MODE_GCM, $this->getKeySize());
36
            $cipher->setAAD(null);
37
            $encrypted_cek = $cipher->encrypt($cek, Base64Url::decode($key->get('k')), $iv);
38
39
            $additional_headers['tag'] = Base64Url::encode($cipher->getTag());
40
        } else {
41
            list($encrypted_cek, $tag) = GCM::encrypt(Base64Url::decode($key->get('k')), $iv, $cek, null);
42
            $additional_headers['tag'] = Base64Url::encode($tag);
43
        }
44
45
        return $encrypted_cek;
46
    }
47
48
    /**
49
     * {@inheritdoc}
50
     */
51
    public function unwrapKey(JWKInterface $key, $encrypted_cek, array $header)
52
    {
53
        $this->checkKey($key);
54
        $this->checkAdditionalParameters($header);
55
56
        if (class_exists('\Crypto\Cipher')) {
57
            $cipher = Cipher::aes(Cipher::MODE_GCM, $this->getKeySize());
58
            $cipher->setTag(Base64Url::decode($header['tag']));
59
            $cipher->setAAD(null);
60
61
            $cek = $cipher->decrypt($encrypted_cek, Base64Url::decode($key->get('k')), Base64Url::decode($header['iv']));
62
63
            return $cek;
64
        }
65
66
        return GCM::decrypt(Base64Url::decode($key->get('k')), Base64Url::decode($header['iv']), $encrypted_cek, null, Base64Url::decode($header['tag']));
67
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72
    public function getKeyManagementMode()
73
    {
74
        return self::MODE_WRAP;
75
    }
76
77
    /**
78
     * @param JWKInterface $key
79
     */
80
    protected function checkKey(JWKInterface $key)
81
    {
82
        if ('oct' !== $key->get('kty') || !$key->has('k')) {
83
            throw new \InvalidArgumentException('The key is not valid');
84
        }
85
    }
86
87
    /**
88
     * @param array $header
89
     */
90
    protected function checkAdditionalParameters(array $header)
91
    {
92
        if (!array_key_exists('iv', $header) || !array_key_exists('tag', $header)) {
93
            throw new \InvalidArgumentException("Missing parameters 'iv' or 'tag'.");
94
        }
95
    }
96
97
    /**
98
     * @return int
99
     */
100
    abstract protected function getKeySize();
101
}
102