25
\$\begingroup\$

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]
\$\endgroup\$
  • \$\begingroup\$ Is [1 2 3 3 3 3] truthy or falsey? I think it should be truthy but I'm not positive. \$\endgroup\$ – James Aug 27 '16 at 16:54
  • \$\begingroup\$ @DJMcMayhem Truthy \$\endgroup\$ – Jakube Aug 27 '16 at 16:58
  • \$\begingroup\$ @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]. \$\endgroup\$ – Sp3000 Aug 27 '16 at 17:24
  • \$\begingroup\$ Surely you meant to put a comma after Hello. (It's in the hex.) \$\endgroup\$ – rici Aug 28 '16 at 3:43
  • \$\begingroup\$ @rici Thanks for noticing, fixed! \$\endgroup\$ – Sp3000 Aug 28 '16 at 3:50

22 Answers 22

8
\$\begingroup\$

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!

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ def f(s)= is a byte shorter. \$\endgroup\$ – ThreeFx Aug 27 '16 at 15:45
  • 2
    \$\begingroup\$ @ThreeFx you need to return? \$\endgroup\$ – Leaky Nun Aug 27 '16 at 15:46
  • \$\begingroup\$ @ThreeFx Yes, but then I have to write return. The lambda version is 7 bytes shorter. \$\endgroup\$ – Copper Aug 27 '16 at 15:47
  • \$\begingroup\$ You're right. Sorry. \$\endgroup\$ – ThreeFx Aug 27 '16 at 15:47
  • \$\begingroup\$ lambda s:[s[-1]]*s[-1]=s[-s[-1]:] \$\endgroup\$ – Leaky Nun Aug 27 '16 at 15:48
7
\$\begingroup\$

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
| improve this answer | |
\$\endgroup\$
7
\$\begingroup\$

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

| improve this answer | |
\$\endgroup\$
7
\$\begingroup\$

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).
| improve this answer | |
\$\endgroup\$
6
\$\begingroup\$

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.
| improve this answer | |
\$\endgroup\$
6
\$\begingroup\$

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!

| improve this answer | |
\$\endgroup\$
5
\$\begingroup\$

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
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ @Adnan Working now \$\endgroup\$ – Luis Mendo Aug 27 '16 at 16:14
  • \$\begingroup\$ Nice, looks good :) \$\endgroup\$ – Adnan Aug 27 '16 at 16:40
  • 2
    \$\begingroup\$ Also, congratulations on 25k! :3 \$\endgroup\$ – Adnan Aug 27 '16 at 16:54
4
\$\begingroup\$

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.

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

Haskell, 50 bytes

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

Takes an array of integers as input.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ You need to import Data.List unless you're in the REPL. \$\endgroup\$ – xnor Aug 27 '16 at 18:32
2
\$\begingroup\$

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
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ @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. \$\endgroup\$ – miles Aug 29 '16 at 11:38
  • \$\begingroup\$ Right, nice catch. I missed that. \$\endgroup\$ – randomra Aug 29 '16 at 11:44
2
\$\begingroup\$

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.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Oh hey, nice to see you on here! Welcome to the site! \$\endgroup\$ – James Aug 28 '16 at 23:26
1
\$\begingroup\$

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.

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

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
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Dyalog APL, 10 bytes

(⊃∧.=⊃↑⊢)⌽

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

TryAPL online!

| improve this answer | |
\$\endgroup\$
  • 2
    \$\begingroup\$ How many bytes? \$\endgroup\$ – Conor O'Brien Aug 28 '16 at 3:32
  • \$\begingroup\$ @ConorO'Brien Sorry, forgot to fill in the boilerplate. \$\endgroup\$ – Adám Aug 28 '16 at 8:11
1
\$\begingroup\$

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]))

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

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).

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Perl 5, 30 bytes

Includes +1 for -p

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

Try it online!

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

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.
| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

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
| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

Pyke, 7 bytes

eQ>}lt!

Try it here!

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

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;
}
| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

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:

((({}))){({}[()]<(({})<([{}]{}<>)<>>)>)}<>([])({<{}>{}<([])>}{})
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.