Completed
Push — master ( 5d9144...6bacde )
by Florent
02:38
created

AESGCMKW::getKeySize()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 1
nc 1
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
        $kek = Base64Url::decode($key->get('k'));
32
        $iv = StringUtil::generateRandomBytes(96 / 8);
33
        $additional_headers['iv'] = Base64Url::encode($iv);
34
35
        if (class_exists('\Crypto\Cipher')) {
36
            $cipher = Cipher::aes(Cipher::MODE_GCM, $this->getKeySize());
37
            $cipher->setAAD(null);
38
            $encrypted_cek = $cipher->encrypt($cek, $kek, $iv);
39
40
            $additional_headers['tag'] = Base64Url::encode($cipher->getTag());
41
        } elseif (version_compare(PHP_VERSION, '7.1.0') >= 0) {
42
            $tag = null;
43
            $encrypted_cek = openssl_encrypt($cek, $this->getMode($kek), $kek, OPENSSL_RAW_DATA, $iv, $tag , null, 16);
44
            $additional_headers['tag'] = Base64Url::encode($tag);
45
        } else {
46
            list($encrypted_cek, $tag) = GCM::encrypt($kek, $iv, $cek, null);
47
            $additional_headers['tag'] = Base64Url::encode($tag);
48
        }
49
50
        return $encrypted_cek;
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56
    public function unwrapKey(JWKInterface $key, $encrypted_cek, array $header)
57
    {
58
        $this->checkKey($key);
59
        $this->checkAdditionalParameters($header);
60
        
61
        $kek = Base64Url::decode($key->get('k'));
62
        $tag = Base64Url::decode($header['tag']);
63
        $iv = Base64Url::decode($header['iv']);
64
65
        if (class_exists('\Crypto\Cipher')) {
66
            $cipher = Cipher::aes(Cipher::MODE_GCM, $this->getKeySize());
67
            $cipher->setTag($tag);
68
            $cipher->setAAD(null);
69
70
            $cek = $cipher->decrypt($encrypted_cek, $kek, $iv);
71
72
            return $cek;
73
        } elseif (version_compare(PHP_VERSION, '7.1.0') >= 0) {
74
            return openssl_decrypt($encrypted_cek, $this->getMode($kek), $kek, OPENSSL_RAW_DATA, $iv, $tag , null);
75
        }
76
77
        return GCM::decrypt($kek, $iv, $encrypted_cek, null, $tag);
78
    }
79
80
    /**
81
     * @param string $k
82
     *
83
     * @return string
84
     */
85
    private function getMode($k)
86
    {
87
        return 'aes-'.(8 *  strlen($k)).'-gcm';
88
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93
    public function getKeyManagementMode()
94
    {
95
        return self::MODE_WRAP;
96
    }
97
98
    /**
99
     * @param JWKInterface $key
100
     */
101
    protected function checkKey(JWKInterface $key)
102
    {
103
        if ('oct' !== $key->get('kty') || !$key->has('k')) {
104
            throw new \InvalidArgumentException('The key is not valid');
105
        }
106
    }
107
108
    /**
109
     * @param array $header
110
     */
111
    protected function checkAdditionalParameters(array $header)
112
    {
113
        if (!array_key_exists('iv', $header) || !array_key_exists('tag', $header)) {
114
            throw new \InvalidArgumentException("Missing parameters 'iv' or 'tag'.");
115
        }
116
    }
117
118
    /**
119
     * @return int
120
     */
121
    abstract protected function getKeySize();
122
}
123