PKCS#7 padding validation

25

In cryptography, PKCS#7 padding is a padding scheme which adds a number of bytes N ≥ 1, where the value of each added byte is equal to N.

For example, Hello, World!, which has 13 bytes, is the following in hex:

48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21

If we choose to PKCS#7 pad to length 16, then the result is:

48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21 03 03 03

And if we choose to pad to length 20, then the result is:

48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21 07 07 07 07 07 07 07

Note that in the first example we add three 03 bytes, and in the second we add seven 07 bytes.

Your task will be to validate whether a string (or integer array) has correct PKCS#7 padding. That is, if the last byte of the input string is N, then your program should check that the last N bytes of the string are equal to N.

Input

A single nonempty ASCII string containing characters between code points 1 and 127 inclusive. If you wish, you may take input as an array of integers instead.

Output

A truthy value if the input string has valid PKCS#7 padding, otherwise a falsy value.

Both functions and full programs are acceptable. This is , so the aim is to minimise the number of bytes in your code.

Test cases

The integer array version of inputs is presented here — the string version would have unprintable characters for many of the following test cases:

Truthy:

[1]
[1, 1]
[2, 1]
[2, 2]
[5, 6, 5, 3, 3, 3]
[1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2]
[95, 115, 80, 32, 71, 7, 122, 49, 13, 7, 7, 7, 7, 7, 7, 7, 7]
[27, 33, 54, 65, 97, 33, 52, 55, 60, 1, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
[15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15]

Falsy:

[2]
[1, 2]
[5, 5, 5, 5]
[5, 6, 5, 4, 4, 4]
[3, 3, 3, 94, 3, 3]
[1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 127]
[50, 39, 94, 105, 49, 29, 74, 102, 2, 106, 44, 7, 7, 7, 7, 7, 7]
[26, 27, 59, 25, 122, 110, 20, 30, 114, 6, 9, 62, 121, 42, 22, 60, 33, 12]

Sp3000

Posted 2016-08-27T15:20:07.520

Reputation: 58 729

Is [1 2 3 3 3 3] truthy or falsey? I think it should be truthy but I'm not positive. – James – 2016-08-27T16:54:54.320

@DJMcMayhem Truthy – Jakube – 2016-08-27T16:58:39.280

@DJMcMayhem Truthy (this parallels the truthy test case ending in 7s). You can think of it as, after stripping, you'd end up with [1 2 3]. – Sp3000 – 2016-08-27T17:24:53.553

Surely you meant to put a comma after Hello. (It's in the hex.) – rici – 2016-08-28T03:43:48.230

@rici Thanks for noticing, fixed! – Sp3000 – 2016-08-28T03:50:36.567

Can I also take the index of the last element of the array as input? Or a pointer to the last element instead of the first (in C)? – Riley – 2016-08-29T15:07:35.767

@Riley Taking a pointer to/index of the last element feels a bit like preprocessing to me, so no. My intention with C was that since 0 will not be in the input, you can assume the array is null terminated. – Sp3000 – 2016-08-29T21:34:49.480

Answers

8

Python, 47 34 33 bytes

lambda s:s[-1:]*s[-1]==s[-s[-1]:]

s[-1] is the last member of the list s. Checks that the last s[-1] members of the input array s are the same as an array of s[-1] repeated that many times.

Takes input as an array of integers. This is a lambda expression; to use it, assign it by prefixing lambda with f=.

Try it on Ideone!

To test:

>>> f=lambda s:s[-1:]*s[-1]==s[-s[-1]:]
>>> f([27, 33, 54, 65, 97, 33, 52, 55, 60, 1, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10])
True
>>> f([50, 39, 94, 105, 49, 29, 74, 102, 2, 106, 44, 7, 7, 7, 7, 7, 7])
False

Saved 13 bytes thanks to Leaky Nun!

Saved a byte thanks to Dennis!

Copper

Posted 2016-08-27T15:20:07.520

Reputation: 3 684

def f(s)= is a byte shorter. – ThreeFx – 2016-08-27T15:45:28.870

2@ThreeFx you need to return? – Leaky Nun – 2016-08-27T15:46:38.390

@ThreeFx Yes, but then I have to write return. The lambda version is 7 bytes shorter. – Copper – 2016-08-27T15:47:07.797

You're right. Sorry. – ThreeFx – 2016-08-27T15:47:29.997

lambda s:[s[-1]]*s[-1]=s[-s[-1]:] – Leaky Nun – 2016-08-27T15:48:51.027

s[-1:]*s[-1] should work. – Dennis – 2016-08-27T16:59:16.770

7

Brachylog, 14 bytes

~c[A:B]t#=h~lB

Try it online!

~c[A:B]t#=h~lB
~c[A:B]                input is concatenation of A and B
       t               B
        #=             has all equal elements
          h~lB         the first item of B is the length of B

Leaky Nun

Posted 2016-08-27T15:20:07.520

Reputation: 45 011

7

Jelly, 5 bytes

ŒgṪṫṪ

Input is an array of code points, output is a non-empty array (truthy) or an empty array (falsy).

Try it online! or verify all test cases.

How it works

ŒgṪṫṪ  Main link. Argument: A (array)

Œg     Group all runs of consecutive, equal integers.
  Ṫ    Tail; yield the last run. It should consist of n or more occurrences of n.
    Ṫ  Tail; yield n, the last element of A.
   ṫ   Dyadic tail; discard everything after the n-th element of the last run.
       If the last run was long enough, this will yield a non-empty array (truthy);
       if not, the result will be an empty array (falsy).

Dennis

Posted 2016-08-27T15:20:07.520

Reputation: 196 637

7

Pyth, 5 bytes

gFer8

RLE on input, take the last pair and check if the number of repeats is greater or equal than the value.

Try it online: Demonstration or Test Suite

Jakube

Posted 2016-08-27T15:20:07.520

Reputation: 21 462

6

CJam, 9 8 bytes

Thanks to Sp3000 for saving 1 byte.

{e`W=:/}

Takes an integer list as input and returns 0 (falsy) or a positive integer (truthy).

Test suite.

Explanation

e`   e# Run-length encoding, yielding pairs of run-length R and value V.
W=   e# Get the last pair.
:/   e# Compute R/V, which is positive iff R ≥ V. Works, because V is guaranteed
     e# to be non-zero.

Martin Ender

Posted 2016-08-27T15:20:07.520

Reputation: 184 808

6

05AB1E, 9 bytes

No run-length encodings for osabie :(

¤sR¬£¬QOQ

Explanation:

¤           # Get the last element of the array
 s          # Swap the two top elements
  R         # Reverse the array
   ¬        # Get the first element
    £       # Substring [0:first element]
     ¬      # Get the first element
      Q     # Check if they are equal
       OQ   # Sum up and check if equal

With an example:

¤           # [5, 6, 5, 3, 3, 3]  3
 s          # 3  [5, 6, 5, 3, 3, 3]
  R         # 3  [3, 3, 3, 5, 6, 5]
   ¬        # 3  [3, 3, 3, 5, 6, 5]  3
    £       # 3  [3, 3, 3]
     ¬      # 3  [3, 3, 3]  3
      Q     # 3  [1, 1, 1]
       OQ   # 3==3 which results into 1

Uses the CP-1252 encoding. Try it online!

Adnan

Posted 2016-08-27T15:20:07.520

Reputation: 41 965

5

MATL, 10 bytes

Thanks to @Adnan for noticing a problem with an earlier version of the code

P0hG0):)&=

When the input has correct padding, the output is an array containing only ones, which is truthy. When it has incorrect padding, the output is an array containing at least a zero, and so is falsy.

Try it online! Or verify all test cases.

Explanation

P     % Implicitly take numeric array as input. Reverse the array
0h    % Append a 0. This ensures falsy output if input array is too short
G0)   % Push input again. Get its last element
:     % Range from 1 to that
)     % Apply as index into the array
&=    % 2D array of all pairwise equality comparisons. Implicitly display

Luis Mendo

Posted 2016-08-27T15:20:07.520

Reputation: 87 464

@Adnan Working now – Luis Mendo – 2016-08-27T16:14:28.270

Nice, looks good :) – Adnan – 2016-08-27T16:40:05.647

2Also, congratulations on 25k! :3 – Adnan – 2016-08-27T16:54:33.030

4

Mathematica, 29 bytes

#&@@#<=Length@#&@*Last@*Split

Split the input into runs of equal elements, extract the last, and check that its first element is less than or equal to the length of that run.

Martin Ender

Posted 2016-08-27T15:20:07.520

Reputation: 184 808

3

Haskell, 50 bytes

import Data.List
((>=)<$>head<*>length).last.group

Takes an array of integers as input.

ThreeFx

Posted 2016-08-27T15:20:07.520

Reputation: 1 435

You need to import Data.List unless you're in the REPL. – xnor – 2016-08-27T18:32:33.503

2

J, 13 bytes

#~@{:-:{:{.|.

Takes the list as a single argument and outputs 1 if it is truthy and 0 if falsey.

Usage

   f =: #~@{:-:{:{.|.
   f 5 6 5 3 3 3
1
   f 5 6 5 4 4 4
0

Explanation

#~@{:-:{:{.|.  Input: array A
           |.  Reverse A
       {:      Get the last value in A
         {.    Take that many values from the reverse of A
   {:          Get the last value in A
#~@            Make a list with that many copies of the last value
     -:        Test if the list of copies matches the sublist of A and return

miles

Posted 2016-08-27T15:20:07.520

Reputation: 15 654

@randomra A case such as 3 4 3 3 3 would have ~. as 3 4 so that the last row of = is 0 1 0 0 0. I think operating on the reverse as {:*/@{.0{=@|. should work, but it ends up as 13 bytes also. – miles – 2016-08-29T11:38:44.590

Right, nice catch. I missed that. – randomra – 2016-08-29T11:44:20.953

2

Brain-Flak, 54 bytes

(({})[()]){({}[()]<({}[({})]){<>}{}>)}{}{<>(<(())>)}{}

Input is a list of integers, output is 1 for truthy and empty for falsey.

Explanation

(({})[()]){ Loop a number of times equal to the last integer in the input - 1
    ({}[()] Handle loop counter
        < Silently...
            ({}[({})]) Replace the last code point in the string with its difference with the code point before it
            {<>} If the difference is not zero then switch stacks
            {} Discard the difference
        > End silently
    ) Handle loop counter
} End loop
{} Discard the loop counter
{<>(<(())>)} If the top of the current stack is not 0 (which means we have not switched stacks push 0 then 1
{} Discard the top of the stack (either nothing if falsey or 0 if truthy)

The loop does not immediately end when a value that would result in a falsey return is encountered. It is instead switched to the other stack which is empty and spends the rest of its iterations comparing 0 and 0.

0 '

Posted 2016-08-27T15:20:07.520

Reputation: 3 439

1Oh hey, nice to see you on here! Welcome to the site! – James – 2016-08-28T23:26:55.437

1

Perl 5, 30 bytes

Includes +1 for -p

#!/usr/bin/perl -p
$_=/(.)\1*\z/s+length$&>ord$1

Try it online!

Ton Hospel

Posted 2016-08-27T15:20:07.520

Reputation: 14 114

1

Brachylog, 6 bytes

a₁=.l∈

Try it online!

Outputs through predicate success or failure, as Leaky Nun's Brachylog v1 answer does. Takes a similar approach, as well, but comes out a lot shorter.

a₁        There exists a suffix of the input
  =       the elements of which are all equal
   .      which is the output variable
    l     the length of which
     ∈    is an element of
          the output variable.

Brachylog, 6 bytes

ḅt.l≥∈

Try it online!

An alternate version that comes out to the same length which takes some inspiration from Dennis' Jelly answer.

 t        The last
ḅ         block of consecutive equal elements of the input
  .       is the output variable
   l      the length of which
    ≥     is greater than or equal to
     ∈    an element of
          the output variable.

Unrelated String

Posted 2016-08-27T15:20:07.520

Reputation: 5 300

1

Batch, 101 bytes

@for %%a in (%*)do @set/an=%%a,c=0
@for %%a in (%*)do @set/ac+=1,c*=!(n-%%a)
@if %c% geq %n% echo 1

Takes input as command-line parameters, loops over them all so that it can get the last one into n, loops over them all again to count the run of trailing ns, finally printing 1 if the count is at least equal to n. Alternatively if printing 0 or a non-zero value is acceptable, then for 93 bytes, change the last line to @cmd/cset/ac/n.

Neil

Posted 2016-08-27T15:20:07.520

Reputation: 95 035

1

Haskell, 49 bytes

f s|x<-(==last s)=x.length.fst.span x.reverse$s

Try it on Ideone.

Shorter version which returns True for truthy and False or an exception for falsy:

((==).head>>=all).(head>>=take).reverse

Laikoni

Posted 2016-08-27T15:20:07.520

Reputation: 23 676

1

Javascript (ES6), 51 47 41 bytes

a=>(r=k=>a.pop()^n?k<2:r(k-1))(n=a.pop())

Examples:

let f =
a=>(r=k=>a.pop()^n?k<2:r(k-1))(n=a.pop())

console.log(f([5, 6, 5, 3, 3, 3]))
console.log(f([5, 6, 5, 4, 4, 4]))

Arnauld

Posted 2016-08-27T15:20:07.520

Reputation: 111 334

1

Dyalog APL, 10 bytes

(⊃∧.=⊃↑⊢)⌽

Is the first
∧.= all-equal to
the first
n taken from
the
reversed argument?

TryAPL online!

Adám

Posted 2016-08-27T15:20:07.520

Reputation: 37 779

2How many bytes? – Conor O'Brien – 2016-08-28T03:32:27.930

@ConorO'Brien Sorry, forgot to fill in the boilerplate. – Adám – 2016-08-28T08:11:58.863

1

C 91 Bytes

int f(int*l){int n;for(n=0;l[++n];);l+=n-1;for(int i=*l;i;)if(l[-i--+1]^*l||n<*l)return 0;}

Input: a pointer to a null-terminated array.
Output: returns 0 for invalid padding and non-zero for valid (the last element in the array)

Examples:

int a[] = {5, 6, 5, 3, 3, 3, 0};
printf("%d\n", f(&a[5], 6));

int b[] = {1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0};
printf("%d\n", f(&b[11],12 ));

int m[] = {5, 6, 5, 4, 4, 4, 0};
printf("%d\n", f(&m[5], 6));

int n[] = {3, 3, 3, 94, 3, 3, 0};
printf("%d\n", f(&n[5], 6));

Gives:

3
2
0
0

This does rely on undefined behavior. If the padding is valid there is no return statement, but using gcc -std=c99 this returns the last element of the array that was passed in (at least on my machine).

Riley

Posted 2016-08-27T15:20:07.520

Reputation: 11 345

0

Retina, 34 bytes

Byte count assumes ISO 8859-1 encoding.

.+
$*
\b(1(1)*)(?<-2>¶\1)*$(?(2)!)

Input is a linefeed-separated list of integers. Prints 0 or 1.

Try it online! (The first line enables a test suite, where there is one space-separated test case per line.)

An alternative idea that ends up at 35 bytes and prints 0 or a positive integer:

.+
$*
\b(?=(1+)(¶\1)*$)(?<-2>1)*1\b

Martin Ender

Posted 2016-08-27T15:20:07.520

Reputation: 184 808

0

Pyke, 7 bytes

eQ>}lt!

Try it here!

Blue

Posted 2016-08-27T15:20:07.520

Reputation: 26 661

0

Javascript (ES5), 89 bytes

function(b){for(var d=b[b.length-1],c=0;c<d;c++)if(b[b.length-c-1]!=d)return!1;return!0};

Ungolfed:

function a(arr){
var b=arr[arr.length-1];
for(var i=0;i<b;i++){
    if(arr[arr.length-i-1]!=b)return false;
}
return true;
}

Paul Schmitz

Posted 2016-08-27T15:20:07.520

Reputation: 1 089

0

Brain-Flak 84 bytes

100000000 beat me here

Try It Online!

((({}))){({}[()]<(({})<([{}]{}<>)<>>)>)}<>([])({<{}>{}<([])>}{}<(())>){((<{}{}>))}{}

Takes input as array of integers.

Explanation to come.

Here is a 64 byte version that outputs the not of the answer:

((({}))){({}[()]<(({})<([{}]{}<>)<>>)>)}<>([])({<{}>{}<([])>}{})

Post Rock Garf Hunter

Posted 2016-08-27T15:20:07.520

Reputation: 55 382