Passed
Push — master ( 59bb35...8722e3 )
by Vincent
04:28
created

fr.arakne.utils.encoding.Key   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 134
Duplicated Lines 0 %

Test Coverage

Coverage 85.29%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 47
c 1
b 0
f 0
dl 0
loc 134
ccs 29
cts 34
cp 0.8529
rs 10
wmc 17

8 Methods

Rating   Name   Duplication   Size   Complexity  
A generate() 0 2 1
A parse(String) 0 15 4
A Key(String) 0 2 1
A generate(int) 0 6 2
A encode() 0 22 4
A generate(int,SecureRandom) 0 8 2
A cipher() 0 6 2
A toString() 0 3 1
1
/*
2
 * This file is part of ArakneUtils.
3
 *
4
 * ArakneUtils is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU Lesser General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * ArakneUtils is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public License
15
 * along with ArakneUtils.  If not, see <https://www.gnu.org/licenses/>.
16
 *
17
 * Copyright (c) 2017-2020 Vincent Quatrevieux
18
 */
19
20
package fr.arakne.utils.encoding;
21
22
import java.io.UnsupportedEncodingException;
23
import java.net.URLDecoder;
24
import java.net.URLEncoder;
25
import java.nio.charset.StandardCharsets;
26
import java.security.SecureRandom;
27
28
/**
29
 * Handle key for Dofus packets
30
 */
31
final public class Key {
32
    static private SecureRandom random;
33
34
    final private String key;
0 ignored issues
show
Comprehensibility introduced by
A field should not duplicate the name of its containing class. While technically legal, this practice may be confusing.
Loading history...
35
    private XorCipher cipher;
36
37 1
    public Key(String key) {
38 1
        this.key = key;
39 1
    }
40
41
    @Override
42
    public String toString() {
43 1
        return key;
44
    }
45
46
    /**
47
     * Get the cipher related to this key
48
     * The cipher instance is saved into the key
49
     *
50
     * @return The cipher instance
51
     */
52
    public XorCipher cipher() {
53 1
        if (cipher == null) {
54 1
            cipher = new XorCipher(key);
55
        }
56
57 1
        return cipher;
58
    }
59
60
    /**
61
     * Encode the key to hexadecimal string
62
     *
63
     * @return The encoded key
64
     * @see Key#parse(String) For parse the encoded key
65
     */
66
    public String encode() {
67
        final String raw;
68
69
        try {
70 1
            raw = URLEncoder.encode(key, StandardCharsets.UTF_8.toString());
71
        } catch (UnsupportedEncodingException e) {
72
            throw new IllegalStateException("Invalid UTF-8 key", e);
73 1
        }
74
75 1
        StringBuilder encrypted = new StringBuilder(raw.length() * 2);
76
77 1
        for (int i = 0; i < raw.length(); ++i) {
78 1
            final char c = raw.charAt(i);
79
80 1
            if (c < 16) {
81
                encrypted.append('0');
82
            }
83
84 1
            encrypted.append(Integer.toHexString(c));
85
        }
86
87 1
        return encrypted.toString();
88
    }
89
90
    /**
91
     * Parse an hexadecimal key string
92
     *
93
     * https://github.com/Emudofus/Dofus/blob/1.29/dofus/aks/Aks.as#L232
94
     *
95
     * @param input Key to parse
96
     *
97
     * @return The key instance
98
     *
99
     * @throws IllegalArgumentException When invalid key is given
100
     * @throws NumberFormatException When invalid hexadecimal string is given
101
     *
102
     * @see Key#encode() For generate the hexadecimal string
103
     */
104
    static public Key parse(String input) {
105 1
        if (input.length() % 2 != 0) {
106 1
            throw new IllegalArgumentException("Invalid key");
107
        }
108
109 1
        final char[] keyArr = new char[input.length() / 2];
110
111 1
        for (int i = 0; i < input.length(); i += 2) {
112 1
            keyArr[i / 2] = (char) Integer.parseInt(input.substring(i, i + 2), 16);
113
        }
114
115
        try {
116 1
            return new Key(URLDecoder.decode(new String(keyArr), StandardCharsets.UTF_8.toString()));
117
        } catch (UnsupportedEncodingException e) {
118
            throw new IllegalArgumentException("Invalid UTF-8 character");
119
        }
120
    }
121
122
    /**
123
     * Generate a new random key, with length of 128 characters
124
     * The generated key contains only displayable characters
125
     *
126
     * @return The generated key
127
     */
128
    static public Key generate() {
129 1
        return generate(128);
130
    }
131
132
    /**
133
     * Generate a new random key
134
     * The generated key contains only displayable characters
135
     *
136
     * @param size The key size
137
     *
138
     * @return The generated key
139
     */
140
    static public Key generate(int size) {
141 1
        if (random == null) {
142 1
            random = new SecureRandom();
143
        }
144
145 1
        return generate(size, random);
146
    }
147
148
    /**
149
     * Generate a new random key
150
     * The generated key contains only displayable characters
151
     *
152
     * @param size The key size
153
     * @param random The random number generator
154
     *
155
     * @return The generated key
156
     */
157
    static public Key generate(int size, SecureRandom random) {
158 1
        final char[] keyArr = new char[size];
159
160 1
        for (int i = 0; i < size; ++i) {
161 1
            keyArr[i] = (char) (random.nextInt(127 - 32) + 32);
162
        }
163
164 1
        return new Key(new String(keyArr));
165
    }
166
}
167