Caesar cipher in i686 assembly + MMX
A big danger.

When the len parameter happens to be a muliple of 8 and all of the full qwords have been processed, there will be no remaining bytes to process.
Your code calculates the number of remaining bytes using

mov 16(%ebp),%edx     # length
...
and $7,%edx           # loop tail


but forgets to exit if this produces zero. The loop that follows is started anyway and at the bottom where it reads

inc %edx
jnz 0b


the increment of %edx will keep producing NZ for a very long time! 

Resolve this by exiting if the and instruction sets ZF=1.

mov 16(%ebp), %edx    # length
...
and $7, %edx          # loop tail
jz  1f




A small optimization


and $~7,%edx        # only process full qwords
test %edx,%edx
jz 1f



Because the and instruction defines the zero flag (ZF), there's no need to write test %edx, %edx. 



Allow me


mov $'A'+26-1,%ah



This struck me as being a bit too much of a complication. Why not simply write

mov $'Z', %ah


Now if it was your intent to come close to the comment that follows in the next line
# ah: threshold ('A' - 1 - (key - 26))
then writing

lea -26(%ecx), %eax   # al: key - 26
mov $'A'-1, %ah
sub %al, %ah          # ah: threshold ('A' - 1 - (key - 26))


would have nailed it.