diff --git a/lib/AESKW/Algorithm.php b/lib/AESKW/Algorithm.php
index 8fec602..19870d8 100644
--- a/lib/AESKW/Algorithm.php
+++ b/lib/AESKW/Algorithm.php
@@ -8,7 +8,8 @@
*
* @link https://tools.ietf.org/html/rfc3394
*/
-abstract class Algorithm implements AESKeyWrapAlgorithm
+abstract class Algorithm implements
+ AESKeyWrapAlgorithm
{
/**
* Default initial value.
@@ -182,19 +183,9 @@ public function unwrapPad($ciphertext, $kek) {
"Ciphertext length must be a multiple of 64 bits.");
}
$this->_checkKEKSize($kek);
+ // split to blocks
$C = str_split($ciphertext, 8);
- $n = count($C) - 1;
- // if key consists of only one block, recover AIV and padded key as:
- // A | P[1] = DEC(K, C[0] | C[1])
- if ($n == 1) {
- $P = str_split($this->_decrypt($kek, $C[0] . $C[1]), 8);
- $A = $P[0];
- unset($P[0]);
- } else {
- // apply normal unwrapping
- list($A, $R) = $this->_unwrapBlocks($C, $kek);
- $P = array_slice($R, 1, null, true);
- }
+ list($P, $A) = $this->_unwrapPaddedBlocks($C, $kek);
// check that MSB(32,A) = A65959A6
$iv = substr($A, 0, 4);
if ($iv != self::AIV_HI) {
@@ -204,7 +195,8 @@ public function unwrapPad($ciphertext, $kek) {
$mli = substr($A, -4);
$len = unpack("N1", $mli)[1];
// check under and overflow
- if ($len <= 8 * ($n - 1) || $len > 8 * $n) {
+ $n = count($P);
+ if (8 * ($n - 1) >= $len || $len > 8 * $n) {
throw new \UnexpectedValueException("Invalid message length.");
}
$output = implode("", $P);
@@ -241,10 +233,12 @@ protected function _checkKEKSize($kek) {
* Uses alternative version of the key wrap procedure described in the RFC.
*
* @link https://tools.ietf.org/html/rfc3394#section-2.2.1
- * @param string[] $P Plaintext, n 64-bit values {P1, P2, ..., Pn}
+ * @param string[] $P Plaintext, n 64-bit values {P1, P2, ...,
+ * Pn}
* @param string $kek Key encryption key
* @param string $iv Initial value
- * @return string[] Ciphertext, (n+1) 64-bit values {C0, C1, ..., Cn}
+ * @return string[] Ciphertext, (n+1) 64-bit values {C0, C1, ...,
+ * Cn}
*/
protected function _wrapBlocks(array $P, $kek, $iv) {
$n = count($P);
@@ -276,6 +270,31 @@ protected function _wrapBlocks(array $P, $kek, $iv) {
return $C;
}
+ /**
+ * Unwrap the padded ciphertext producing plaintext and integrity value.
+ *
+ * @param string[] $C Ciphertext, (n+1) 64-bit values {C0, C1, ...,
+ * Cn}
+ * @param string $kek Encryption key
+ * @return array Tuple of plaintext P
and integrity value
+ * A
+ */
+ protected function _unwrapPaddedBlocks(array $C, $kek) {
+ $n = count($C) - 1;
+ // if key consists of only one block, recover AIV and padded key as:
+ // A | P[1] = DEC(K, C[0] | C[1])
+ if ($n == 1) {
+ $P = str_split($this->_decrypt($kek, $C[0] . $C[1]), 8);
+ $A = $P[0];
+ unset($P[0]);
+ } else {
+ // apply normal unwrapping
+ list($A, $R) = $this->_unwrapBlocks($C, $kek);
+ $P = array_slice($R, 1, null, true);
+ }
+ return [$P, $A];
+ }
+
/**
* Apply Key Unwrap to data blocks.
*
@@ -285,10 +304,12 @@ protected function _wrapBlocks(array $P, $kek, $iv) {
* Does not compute step 3.
*
* @link https://tools.ietf.org/html/rfc3394#section-2.2.2
- * @param string[] $C Ciphertext, (n+1) 64-bit values {C0, C1, ..., Cn}
+ * @param string[] $C Ciphertext, (n+1) 64-bit values {C0, C1, ...,
+ * Cn}
* @param string $kek Key encryption key
* @throws \UnexpectedValueException
- * @return array Tuple of A and R
+ * @return array Tuple of integrity value A
and register
+ * R
*/
protected function _unwrapBlocks(array $C, $kek) {
$n = count($C) - 1;