$@ isn't a real array - it's a shell "Special Parameter", and you need to be a bit more careful with it than other arrays.
The reason for the behaviour you're seeing is that the exact behaviour of the ${parameter:length:offset} syntax is special-cased when parameter is @, and the behaviour is not consistent with the behaviour you'd get if @ was a real array.
Here's the relevant documentation (bold emphasis mine):
${parameter:offset:length}
... If parameter is @, the result is length positional parameters beginning at offset. If parameter is @, the result is length positional parameters beginning at offset. ...
The positional parameters are $0, $1, $2, ..., so with this syntax it's behaving as if $@ contained the script name ($0) as well as the parameters to the script ($1, $2, ...). This is inconsistent with "$@" expanding to "$1" "$2" ..., but that's life.
You should be able to simplify things (and fix the script) by making a new array instead of using $@ directly, i.e.
new_array=("$@")
for (( i = 0; i < ${#new_array}; i++ )); do
hash=$(md5 -q ${new_array[@]:$i:1})
modifiedNames[$i]=${new_array[@]:$i:1}$hash
done
echo ${modifiedNames[1]}